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 {
|
||||
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 License = "GPLv3";
|
||||
static const string Website = "http://byuu.org/";
|
||||
|
||||
//incremented only when serialization format changes
|
||||
static const string SerializerVersion = "099.07";
|
||||
static const string SerializerVersion = "099.14";
|
||||
}
|
||||
|
||||
#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)
|
||||
#define privileged public
|
||||
#else
|
||||
|
|
|
@ -49,7 +49,7 @@ struct Interface {
|
|||
virtual auto audioSample(const double*, uint) -> void {}
|
||||
virtual auto inputPoll(uint, uint, uint) -> int16 { return 0; }
|
||||
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"); }
|
||||
};
|
||||
Bind* bind = nullptr;
|
||||
|
@ -62,7 +62,7 @@ struct Interface {
|
|||
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 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)...}); }
|
||||
|
||||
//information
|
||||
|
|
|
@ -169,8 +169,8 @@ auto Interface::cheatSet(const lstring& list) -> void {
|
|||
lstring codes = codeset.split("+");
|
||||
for(auto& code : codes) {
|
||||
lstring part = code.split("/");
|
||||
if(part.size() == 2) cheat.append(hex(part[0]), hex(part[1]));
|
||||
if(part.size() == 3) cheat.append(hex(part[0]), hex(part[1]), hex(part[2]));
|
||||
if(part.size() == 2) cheat.append(part[0].hex(), part[1].hex());
|
||||
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("+");
|
||||
for(auto& code : codes) {
|
||||
lstring part = code.split("/");
|
||||
if(part.size() == 2) cheat.append(hex(part[0]), hex(part[1]));
|
||||
if(part.size() == 3) cheat.append(hex(part[0]), hex(part[1]), hex(part[2]));
|
||||
if(part.size() == 2) cheat.append(part[0].hex(), part[1].hex());
|
||||
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 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.s.w, 4), hex(r.d.w, 4), hex(r.db, 2)
|
||||
});
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
auto R65816::op_nop() {
|
||||
L ioIRQ();
|
||||
L idleIRQ();
|
||||
}
|
||||
|
||||
auto R65816::op_wdm() {
|
||||
|
@ -7,11 +7,9 @@ L readPC();
|
|||
}
|
||||
|
||||
auto R65816::op_xba() {
|
||||
io();
|
||||
L io();
|
||||
r.a.l ^= r.a.h;
|
||||
r.a.h ^= r.a.l;
|
||||
r.a.l ^= r.a.h;
|
||||
idle();
|
||||
L idle();
|
||||
r.a.w = r.a.w >> 8 | r.a.w << 8;
|
||||
r.p.n = (r.a.l & 0x80);
|
||||
r.p.z = (r.a.l == 0);
|
||||
}
|
||||
|
@ -22,10 +20,10 @@ auto R65816::op_move_b(int adjust) {
|
|||
r.db = dp;
|
||||
rd.l = readLong(sp << 16 | r.x.w);
|
||||
writeLong(dp << 16 | r.y.w, rd.l);
|
||||
io();
|
||||
idle();
|
||||
r.x.l += adjust;
|
||||
r.y.l += adjust;
|
||||
L io();
|
||||
L idle();
|
||||
if(r.a.w--) r.pc.w -= 3;
|
||||
}
|
||||
|
||||
|
@ -35,10 +33,10 @@ auto R65816::op_move_w(int adjust) {
|
|||
r.db = dp;
|
||||
rd.l = readLong(sp << 16 | r.x.w);
|
||||
writeLong(dp << 16 | r.y.w, rd.l);
|
||||
io();
|
||||
idle();
|
||||
r.x.w += adjust;
|
||||
r.y.w += adjust;
|
||||
L io();
|
||||
L idle();
|
||||
if(r.a.w--) r.pc.w -= 3;
|
||||
}
|
||||
|
||||
|
@ -57,20 +55,20 @@ L r.pc.h = readLong(vector + 1);
|
|||
|
||||
auto R65816::op_stp() {
|
||||
while(r.wai = true) {
|
||||
L io();
|
||||
L idle();
|
||||
}
|
||||
}
|
||||
|
||||
auto R65816::op_wai() {
|
||||
r.wai = true;
|
||||
while(r.wai) {
|
||||
L io();
|
||||
L idle();
|
||||
}
|
||||
io();
|
||||
idle();
|
||||
}
|
||||
|
||||
auto R65816::op_xce() {
|
||||
L ioIRQ();
|
||||
L idleIRQ();
|
||||
bool carry = r.p.c;
|
||||
r.p.c = r.e;
|
||||
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) {
|
||||
L ioIRQ();
|
||||
L idleIRQ();
|
||||
r.p |= 1 << bit;
|
||||
}
|
||||
|
||||
auto R65816::op_clear_flag(uint bit) {
|
||||
L ioIRQ();
|
||||
L idleIRQ();
|
||||
r.p &= ~(1 << bit);
|
||||
}
|
||||
|
||||
auto R65816::op_pflag(bool mode) {
|
||||
rd.l = readPC();
|
||||
L io();
|
||||
L idle();
|
||||
r.p = (mode ? r.p | rd.l : r.p & ~rd.l);
|
||||
E r.p.m = 1, r.p.x = 1;
|
||||
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) {
|
||||
L ioIRQ();
|
||||
L idleIRQ();
|
||||
to.l = from.l;
|
||||
r.p.n = (to.l & 0x80);
|
||||
r.p.z = (to.l == 0);
|
||||
}
|
||||
|
||||
auto R65816::op_transfer_w(Reg16& from, Reg16& to) {
|
||||
L ioIRQ();
|
||||
L idleIRQ();
|
||||
to.w = from.w;
|
||||
r.p.n = (to.w & 0x8000);
|
||||
r.p.z = (to.w == 0);
|
||||
}
|
||||
|
||||
auto R65816::op_tcs() {
|
||||
L ioIRQ();
|
||||
L idleIRQ();
|
||||
r.s.w = r.a.w;
|
||||
E r.s.h = 0x01;
|
||||
}
|
||||
|
||||
auto R65816::op_tsx_b() {
|
||||
L ioIRQ();
|
||||
L idleIRQ();
|
||||
r.x.l = r.s.l;
|
||||
r.p.n = (r.x.l & 0x80);
|
||||
r.p.z = (r.x.l == 0);
|
||||
}
|
||||
|
||||
auto R65816::op_tsx_w() {
|
||||
L ioIRQ();
|
||||
L idleIRQ();
|
||||
r.x.w = r.s.w;
|
||||
r.p.n = (r.x.w & 0x8000);
|
||||
r.p.z = (r.x.w == 0);
|
||||
}
|
||||
|
||||
auto R65816::op_txs() {
|
||||
L ioIRQ();
|
||||
L idleIRQ();
|
||||
E r.s.l = r.x.l;
|
||||
N r.s.w = r.x.w;
|
||||
}
|
||||
|
||||
auto R65816::op_push_b(Reg16& reg) {
|
||||
io();
|
||||
idle();
|
||||
L writeSP(reg.l);
|
||||
}
|
||||
|
||||
auto R65816::op_push_w(Reg16& reg) {
|
||||
io();
|
||||
idle();
|
||||
writeSP(reg.h);
|
||||
L writeSP(reg.l);
|
||||
}
|
||||
|
||||
auto R65816::op_phd() {
|
||||
io();
|
||||
idle();
|
||||
writeSPn(r.d.h);
|
||||
L writeSPn(r.d.l);
|
||||
E r.s.h = 0x01;
|
||||
}
|
||||
|
||||
auto R65816::op_phb() {
|
||||
io();
|
||||
idle();
|
||||
L writeSP(r.db);
|
||||
}
|
||||
|
||||
auto R65816::op_phk() {
|
||||
io();
|
||||
idle();
|
||||
L writeSP(r.pc.b);
|
||||
}
|
||||
|
||||
auto R65816::op_php() {
|
||||
io();
|
||||
idle();
|
||||
L writeSP(r.p);
|
||||
}
|
||||
|
||||
auto R65816::op_pull_b(Reg16& reg) {
|
||||
io();
|
||||
io();
|
||||
idle();
|
||||
idle();
|
||||
L reg.l = readSP();
|
||||
r.p.n = (reg.l & 0x80);
|
||||
r.p.z = (reg.l == 0);
|
||||
}
|
||||
|
||||
auto R65816::op_pull_w(Reg16& reg) {
|
||||
io();
|
||||
io();
|
||||
idle();
|
||||
idle();
|
||||
reg.l = readSP();
|
||||
L reg.h = readSP();
|
||||
r.p.n = (reg.w & 0x8000);
|
||||
|
@ -200,8 +193,8 @@ L reg.h = readSP();
|
|||
}
|
||||
|
||||
auto R65816::op_pld() {
|
||||
io();
|
||||
io();
|
||||
idle();
|
||||
idle();
|
||||
r.d.l = readSPn();
|
||||
L r.d.h = readSPn();
|
||||
r.p.n = (r.d.w & 0x8000);
|
||||
|
@ -210,16 +203,16 @@ E r.s.h = 0x01;
|
|||
}
|
||||
|
||||
auto R65816::op_plb() {
|
||||
io();
|
||||
io();
|
||||
idle();
|
||||
idle();
|
||||
L r.db = readSP();
|
||||
r.p.n = (r.db & 0x80);
|
||||
r.p.z = (r.db == 0);
|
||||
}
|
||||
|
||||
auto R65816::op_plp() {
|
||||
io();
|
||||
io();
|
||||
idle();
|
||||
idle();
|
||||
L r.p = readSP();
|
||||
E r.p.m = 1, r.p.x = 1;
|
||||
if(r.p.x) {
|
||||
|
@ -238,7 +231,7 @@ E r.s.h = 0x01;
|
|||
|
||||
auto R65816::op_pei() {
|
||||
dp = readPC();
|
||||
io2();
|
||||
idle2();
|
||||
aa.l = readDPn(dp + 0);
|
||||
aa.h = readDPn(dp + 1);
|
||||
writeSPn(aa.h);
|
||||
|
@ -249,7 +242,7 @@ E r.s.h = 0x01;
|
|||
auto R65816::op_per() {
|
||||
aa.l = readPC();
|
||||
aa.h = readPC();
|
||||
io();
|
||||
idle();
|
||||
rd.w = r.pc.d + (int16)aa.w;
|
||||
writeSPn(rd.h);
|
||||
L writeSPn(rd.l);
|
||||
|
|
|
@ -4,8 +4,8 @@ L rd.l = readPC();
|
|||
} else {
|
||||
rd.l = readPC();
|
||||
aa.w = r.pc.d + (int8)rd.l;
|
||||
io6(aa.w);
|
||||
L io();
|
||||
idle6(aa.w);
|
||||
L idle();
|
||||
r.pc.w = aa.w;
|
||||
}
|
||||
}
|
||||
|
@ -13,15 +13,15 @@ L io();
|
|||
auto R65816::op_bra() {
|
||||
rd.l = readPC();
|
||||
aa.w = r.pc.d + (int8)rd.l;
|
||||
io6(aa.w);
|
||||
L io();
|
||||
idle6(aa.w);
|
||||
L idle();
|
||||
r.pc.w = aa.w;
|
||||
}
|
||||
|
||||
auto R65816::op_brl() {
|
||||
rd.l = readPC();
|
||||
rd.h = readPC();
|
||||
L io();
|
||||
L idle();
|
||||
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() {
|
||||
aa.l = readPC();
|
||||
aa.h = readPC();
|
||||
io();
|
||||
idle();
|
||||
rd.l = readPB(aa.w + r.x.w + 0);
|
||||
L rd.h = readPB(aa.w + r.x.w + 1);
|
||||
r.pc.w = rd.w;
|
||||
|
@ -67,7 +67,7 @@ L rd.b = readAddr(aa.w + 2);
|
|||
auto R65816::op_jsr_addr() {
|
||||
aa.l = readPC();
|
||||
aa.h = readPC();
|
||||
io();
|
||||
idle();
|
||||
r.pc.w--;
|
||||
writeSP(r.pc.h);
|
||||
L writeSP(r.pc.l);
|
||||
|
@ -78,7 +78,7 @@ auto R65816::op_jsr_long() {
|
|||
aa.l = readPC();
|
||||
aa.h = readPC();
|
||||
writeSPn(r.pc.b);
|
||||
io();
|
||||
idle();
|
||||
aa.b = readPC();
|
||||
r.pc.w--;
|
||||
writeSPn(r.pc.h);
|
||||
|
@ -92,7 +92,7 @@ auto R65816::op_jsr_iaddrx() {
|
|||
writeSPn(r.pc.h);
|
||||
writeSPn(r.pc.l);
|
||||
aa.h = readPC();
|
||||
io();
|
||||
idle();
|
||||
rd.l = readPB(aa.w + r.x.w + 0);
|
||||
L rd.h = readPB(aa.w + r.x.w + 1);
|
||||
r.pc.w = rd.w;
|
||||
|
@ -100,8 +100,8 @@ E r.s.h = 0x01;
|
|||
}
|
||||
|
||||
auto R65816::op_rti() {
|
||||
io();
|
||||
io();
|
||||
idle();
|
||||
idle();
|
||||
r.p = readSP();
|
||||
E r.p.m = 1, r.p.x = 1;
|
||||
if(r.p.x) {
|
||||
|
@ -118,17 +118,17 @@ E r.p.m = 1, r.p.x = 1;
|
|||
}
|
||||
|
||||
auto R65816::op_rts() {
|
||||
io();
|
||||
io();
|
||||
idle();
|
||||
idle();
|
||||
rd.l = readSP();
|
||||
rd.h = readSP();
|
||||
L io();
|
||||
L idle();
|
||||
r.pc.w = ++rd.w;
|
||||
}
|
||||
|
||||
auto R65816::op_rtl() {
|
||||
io();
|
||||
io();
|
||||
idle();
|
||||
idle();
|
||||
rd.l = readSPn();
|
||||
rd.h = readSPn();
|
||||
L rd.b = readSPn();
|
||||
|
|
|
@ -38,7 +38,7 @@ L rd.h = readDB(aa.w + 1);
|
|||
auto R65816::op_read_addrx_b(fp op) {
|
||||
aa.l = 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);
|
||||
call(op);
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ L rd.l = readDB(aa.w + r.x.w);
|
|||
auto R65816::op_read_addrx_w(fp op) {
|
||||
aa.l = 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);
|
||||
L rd.h = readDB(aa.w + r.x.w + 1);
|
||||
call(op);
|
||||
|
@ -55,7 +55,7 @@ L rd.h = readDB(aa.w + r.x.w + 1);
|
|||
auto R65816::op_read_addry_b(fp op) {
|
||||
aa.l = 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);
|
||||
call(op);
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ L rd.l = readDB(aa.w + r.y.w);
|
|||
auto R65816::op_read_addry_w(fp op) {
|
||||
aa.l = 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);
|
||||
L rd.h = readDB(aa.w + r.y.w + 1);
|
||||
call(op);
|
||||
|
@ -105,14 +105,14 @@ L rd.h = readLong(aa.d + r.x.w + 1);
|
|||
|
||||
auto R65816::op_read_dp_b(fp op) {
|
||||
dp = readPC();
|
||||
io2();
|
||||
idle2();
|
||||
L rd.l = readDP(dp);
|
||||
call(op);
|
||||
}
|
||||
|
||||
auto R65816::op_read_dp_w(fp op) {
|
||||
dp = readPC();
|
||||
io2();
|
||||
idle2();
|
||||
rd.l = readDP(dp + 0);
|
||||
L rd.h = readDP(dp + 1);
|
||||
call(op);
|
||||
|
@ -120,16 +120,16 @@ L rd.h = readDP(dp + 1);
|
|||
|
||||
auto R65816::op_read_dpr_b(fp op, Reg16& reg) {
|
||||
dp = readPC();
|
||||
io2();
|
||||
io();
|
||||
idle2();
|
||||
idle();
|
||||
L rd.l = readDP(dp + reg.w);
|
||||
call(op);
|
||||
}
|
||||
|
||||
auto R65816::op_read_dpr_w(fp op, Reg16& reg) {
|
||||
dp = readPC();
|
||||
io2();
|
||||
io();
|
||||
idle2();
|
||||
idle();
|
||||
rd.l = readDP(dp + reg.w + 0);
|
||||
L rd.h = readDP(dp + reg.w + 1);
|
||||
call(op);
|
||||
|
@ -137,7 +137,7 @@ L rd.h = readDP(dp + reg.w + 1);
|
|||
|
||||
auto R65816::op_read_idp_b(fp op) {
|
||||
dp = readPC();
|
||||
io2();
|
||||
idle2();
|
||||
aa.l = readDP(dp + 0);
|
||||
aa.h = readDP(dp + 1);
|
||||
L rd.l = readDB(aa.w);
|
||||
|
@ -146,7 +146,7 @@ L rd.l = readDB(aa.w);
|
|||
|
||||
auto R65816::op_read_idp_w(fp op) {
|
||||
dp = readPC();
|
||||
io2();
|
||||
idle2();
|
||||
aa.l = readDP(dp + 0);
|
||||
aa.h = readDP(dp + 1);
|
||||
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) {
|
||||
dp = readPC();
|
||||
io2();
|
||||
io();
|
||||
idle2();
|
||||
idle();
|
||||
aa.l = readDP(dp + r.x.w + 0);
|
||||
aa.h = readDP(dp + r.x.w + 1);
|
||||
L rd.l = readDB(aa.w);
|
||||
|
@ -166,8 +166,8 @@ L rd.l = readDB(aa.w);
|
|||
|
||||
auto R65816::op_read_idpx_w(fp op) {
|
||||
dp = readPC();
|
||||
io2();
|
||||
io();
|
||||
idle2();
|
||||
idle();
|
||||
aa.l = readDP(dp + r.x.w + 0);
|
||||
aa.h = readDP(dp + r.x.w + 1);
|
||||
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) {
|
||||
dp = readPC();
|
||||
io2();
|
||||
idle2();
|
||||
aa.l = readDP(dp + 0);
|
||||
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);
|
||||
call(op);
|
||||
}
|
||||
|
||||
auto R65816::op_read_idpy_w(fp op) {
|
||||
dp = readPC();
|
||||
io2();
|
||||
idle2();
|
||||
aa.l = readDP(dp + 0);
|
||||
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);
|
||||
L rd.h = readDB(aa.w + r.y.w + 1);
|
||||
call(op);
|
||||
|
@ -198,7 +198,7 @@ L rd.h = readDB(aa.w + r.y.w + 1);
|
|||
|
||||
auto R65816::op_read_ildp_b(fp op) {
|
||||
dp = readPC();
|
||||
io2();
|
||||
idle2();
|
||||
aa.l = readDPn(dp + 0);
|
||||
aa.h = readDPn(dp + 1);
|
||||
aa.b = readDPn(dp + 2);
|
||||
|
@ -208,7 +208,7 @@ L rd.l = readLong(aa.d);
|
|||
|
||||
auto R65816::op_read_ildp_w(fp op) {
|
||||
dp = readPC();
|
||||
io2();
|
||||
idle2();
|
||||
aa.l = readDPn(dp + 0);
|
||||
aa.h = readDPn(dp + 1);
|
||||
aa.b = readDPn(dp + 2);
|
||||
|
@ -219,7 +219,7 @@ L rd.h = readLong(aa.d + 1);
|
|||
|
||||
auto R65816::op_read_ildpy_b(fp op) {
|
||||
dp = readPC();
|
||||
io2();
|
||||
idle2();
|
||||
aa.l = readDPn(dp + 0);
|
||||
aa.h = readDPn(dp + 1);
|
||||
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) {
|
||||
dp = readPC();
|
||||
io2();
|
||||
idle2();
|
||||
aa.l = readDPn(dp + 0);
|
||||
aa.h = readDPn(dp + 1);
|
||||
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) {
|
||||
sp = readPC();
|
||||
io();
|
||||
idle();
|
||||
L rd.l = readSP(sp);
|
||||
call(op);
|
||||
}
|
||||
|
||||
auto R65816::op_read_sr_w(fp op) {
|
||||
sp = readPC();
|
||||
io();
|
||||
idle();
|
||||
rd.l = readSP(sp + 0);
|
||||
L rd.h = readSP(sp + 1);
|
||||
call(op);
|
||||
|
@ -255,20 +255,20 @@ L rd.h = readSP(sp + 1);
|
|||
|
||||
auto R65816::op_read_isry_b(fp op) {
|
||||
sp = readPC();
|
||||
io();
|
||||
idle();
|
||||
aa.l = readSP(sp + 0);
|
||||
aa.h = readSP(sp + 1);
|
||||
io();
|
||||
idle();
|
||||
L rd.l = readDB(aa.w + r.y.w);
|
||||
call(op);
|
||||
}
|
||||
|
||||
auto R65816::op_read_isry_w(fp op) {
|
||||
sp = readPC();
|
||||
io();
|
||||
idle();
|
||||
aa.l = readSP(sp + 0);
|
||||
aa.h = readSP(sp + 1);
|
||||
io();
|
||||
idle();
|
||||
rd.l = readDB(aa.w + r.y.w + 0);
|
||||
L rd.h = readDB(aa.w + r.y.w + 1);
|
||||
call(op);
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
auto R65816::op_adjust_imm_b(Reg16& reg, int adjust) {
|
||||
L ioIRQ();
|
||||
L idleIRQ();
|
||||
reg.l += adjust;
|
||||
r.p.n = (reg.l & 0x80);
|
||||
r.p.z = (reg.l == 0);
|
||||
}
|
||||
|
||||
auto R65816::op_adjust_imm_w(Reg16& reg, int adjust) {
|
||||
L ioIRQ();
|
||||
L idleIRQ();
|
||||
reg.w += adjust;
|
||||
r.p.n = (reg.w & 0x8000);
|
||||
r.p.z = (reg.w == 0);
|
||||
}
|
||||
|
||||
auto R65816::op_asl_imm_b() {
|
||||
L ioIRQ();
|
||||
L idleIRQ();
|
||||
r.p.c = (r.a.l & 0x80);
|
||||
r.a.l <<= 1;
|
||||
r.p.n = (r.a.l & 0x80);
|
||||
|
@ -21,7 +21,7 @@ L ioIRQ();
|
|||
}
|
||||
|
||||
auto R65816::op_asl_imm_w() {
|
||||
L ioIRQ();
|
||||
L idleIRQ();
|
||||
r.p.c = (r.a.w & 0x8000);
|
||||
r.a.w <<= 1;
|
||||
r.p.n = (r.a.w & 0x8000);
|
||||
|
@ -29,7 +29,7 @@ L ioIRQ();
|
|||
}
|
||||
|
||||
auto R65816::op_lsr_imm_b() {
|
||||
L ioIRQ();
|
||||
L idleIRQ();
|
||||
r.p.c = (r.a.l & 0x01);
|
||||
r.a.l >>= 1;
|
||||
r.p.n = (r.a.l & 0x80);
|
||||
|
@ -37,7 +37,7 @@ L ioIRQ();
|
|||
}
|
||||
|
||||
auto R65816::op_lsr_imm_w() {
|
||||
L ioIRQ();
|
||||
L idleIRQ();
|
||||
r.p.c = (r.a.w & 0x0001);
|
||||
r.a.w >>= 1;
|
||||
r.p.n = (r.a.w & 0x8000);
|
||||
|
@ -45,7 +45,7 @@ L ioIRQ();
|
|||
}
|
||||
|
||||
auto R65816::op_rol_imm_b() {
|
||||
L ioIRQ();
|
||||
L idleIRQ();
|
||||
bool carry = r.p.c;
|
||||
r.p.c = (r.a.l & 0x80);
|
||||
r.a.l = (r.a.l << 1) | carry;
|
||||
|
@ -54,7 +54,7 @@ L ioIRQ();
|
|||
}
|
||||
|
||||
auto R65816::op_rol_imm_w() {
|
||||
L ioIRQ();
|
||||
L idleIRQ();
|
||||
bool carry = r.p.c;
|
||||
r.p.c = (r.a.w & 0x8000);
|
||||
r.a.w = (r.a.w << 1) | carry;
|
||||
|
@ -63,7 +63,7 @@ L ioIRQ();
|
|||
}
|
||||
|
||||
auto R65816::op_ror_imm_b() {
|
||||
L ioIRQ();
|
||||
L idleIRQ();
|
||||
bool carry = r.p.c;
|
||||
r.p.c = (r.a.l & 0x01);
|
||||
r.a.l = (carry << 7) | (r.a.l >> 1);
|
||||
|
@ -72,7 +72,7 @@ L ioIRQ();
|
|||
}
|
||||
|
||||
auto R65816::op_ror_imm_w() {
|
||||
L ioIRQ();
|
||||
L idleIRQ();
|
||||
bool carry = r.p.c;
|
||||
r.p.c = (r.a.w & 0x0001);
|
||||
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.h = readPC();
|
||||
rd.l = readDB(aa.w);
|
||||
io();
|
||||
idle();
|
||||
call(op);
|
||||
L writeDB(aa.w, rd.l);
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ auto R65816::op_adjust_addr_w(fp op) {
|
|||
aa.h = readPC();
|
||||
rd.l = readDB(aa.w + 0);
|
||||
rd.h = readDB(aa.w + 1);
|
||||
io();
|
||||
idle();
|
||||
call(op);
|
||||
writeDB(aa.w + 1, rd.h);
|
||||
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) {
|
||||
aa.l = readPC();
|
||||
aa.h = readPC();
|
||||
io();
|
||||
idle();
|
||||
rd.l = readDB(aa.w + r.x.w);
|
||||
io();
|
||||
idle();
|
||||
call(op);
|
||||
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) {
|
||||
aa.l = readPC();
|
||||
aa.h = readPC();
|
||||
io();
|
||||
idle();
|
||||
rd.l = readDB(aa.w + r.x.w + 0);
|
||||
rd.h = readDB(aa.w + r.x.w + 1);
|
||||
io();
|
||||
idle();
|
||||
call(op);
|
||||
writeDB(aa.w + r.x.w + 1, rd.h);
|
||||
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) {
|
||||
dp = readPC();
|
||||
io2();
|
||||
idle2();
|
||||
rd.l = readDP(dp);
|
||||
io();
|
||||
idle();
|
||||
call(op);
|
||||
L writeDP(dp, rd.l);
|
||||
}
|
||||
|
||||
auto R65816::op_adjust_dp_w(fp op) {
|
||||
dp = readPC();
|
||||
io2();
|
||||
idle2();
|
||||
rd.l = readDP(dp + 0);
|
||||
rd.h = readDP(dp + 1);
|
||||
io();
|
||||
idle();
|
||||
call(op);
|
||||
writeDP(dp + 1, rd.h);
|
||||
L writeDP(dp + 0, rd.l);
|
||||
|
@ -144,21 +144,21 @@ L writeDP(dp + 0, rd.l);
|
|||
|
||||
auto R65816::op_adjust_dpx_b(fp op) {
|
||||
dp = readPC();
|
||||
io2();
|
||||
io();
|
||||
idle2();
|
||||
idle();
|
||||
rd.l = readDP(dp + r.x.w);
|
||||
io();
|
||||
idle();
|
||||
call(op);
|
||||
L writeDP(dp + r.x.w, rd.l);
|
||||
}
|
||||
|
||||
auto R65816::op_adjust_dpx_w(fp op) {
|
||||
dp = readPC();
|
||||
io2();
|
||||
io();
|
||||
idle2();
|
||||
idle();
|
||||
rd.l = readDP(dp + r.x.w + 0);
|
||||
rd.h = readDP(dp + r.x.w + 1);
|
||||
io();
|
||||
idle();
|
||||
call(op);
|
||||
writeDP(dp + r.x.w + 1, rd.h);
|
||||
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) {
|
||||
aa.l = readPC();
|
||||
aa.h = readPC();
|
||||
io();
|
||||
idle();
|
||||
L writeDB(aa.w + idx, reg);
|
||||
}
|
||||
|
||||
auto R65816::op_write_addrr_w(Reg16& reg, Reg16& idx) {
|
||||
aa.l = readPC();
|
||||
aa.h = readPC();
|
||||
io();
|
||||
idle();
|
||||
writeDB(aa.w + idx + 0, reg >> 0);
|
||||
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) {
|
||||
dp = readPC();
|
||||
io2();
|
||||
idle2();
|
||||
L writeDP(dp, reg);
|
||||
}
|
||||
|
||||
auto R65816::op_write_dp_w(Reg16& reg) {
|
||||
dp = readPC();
|
||||
io2();
|
||||
idle2();
|
||||
writeDP(dp + 0, reg >> 0);
|
||||
L writeDP(dp + 1, reg >> 8);
|
||||
}
|
||||
|
||||
auto R65816::op_write_dpr_b(Reg16& reg, Reg16& idx) {
|
||||
dp = readPC();
|
||||
io2();
|
||||
io();
|
||||
idle2();
|
||||
idle();
|
||||
L writeDP(dp + idx, reg);
|
||||
}
|
||||
|
||||
auto R65816::op_write_dpr_w(Reg16& reg, Reg16& idx) {
|
||||
dp = readPC();
|
||||
io2();
|
||||
io();
|
||||
idle2();
|
||||
idle();
|
||||
writeDP(dp + idx + 0, reg >> 0);
|
||||
L writeDP(dp + idx + 1, reg >> 8);
|
||||
}
|
||||
|
||||
auto R65816::op_sta_idp_b() {
|
||||
dp = readPC();
|
||||
io2();
|
||||
idle2();
|
||||
aa.l = readDP(dp + 0);
|
||||
aa.h = readDP(dp + 1);
|
||||
L writeDB(aa.w, r.a.l);
|
||||
|
@ -79,7 +79,7 @@ L writeDB(aa.w, r.a.l);
|
|||
|
||||
auto R65816::op_sta_idp_w() {
|
||||
dp = readPC();
|
||||
io2();
|
||||
idle2();
|
||||
aa.l = readDP(dp + 0);
|
||||
aa.h = readDP(dp + 1);
|
||||
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() {
|
||||
dp = readPC();
|
||||
io2();
|
||||
idle2();
|
||||
aa.l = readDPn(dp + 0);
|
||||
aa.h = readDPn(dp + 1);
|
||||
aa.b = readDPn(dp + 2);
|
||||
|
@ -97,7 +97,7 @@ L writeLong(aa.d, r.a.l);
|
|||
|
||||
auto R65816::op_sta_ildp_w() {
|
||||
dp = readPC();
|
||||
io2();
|
||||
idle2();
|
||||
aa.l = readDPn(dp + 0);
|
||||
aa.h = readDPn(dp + 1);
|
||||
aa.b = readDPn(dp + 2);
|
||||
|
@ -107,8 +107,8 @@ L writeLong(aa.d + 1, r.a.h);
|
|||
|
||||
auto R65816::op_sta_idpx_b() {
|
||||
dp = readPC();
|
||||
io2();
|
||||
io();
|
||||
idle2();
|
||||
idle();
|
||||
aa.l = readDP(dp + r.x.w + 0);
|
||||
aa.h = readDP(dp + r.x.w + 1);
|
||||
L writeDB(aa.w, r.a.l);
|
||||
|
@ -116,8 +116,8 @@ L writeDB(aa.w, r.a.l);
|
|||
|
||||
auto R65816::op_sta_idpx_w() {
|
||||
dp = readPC();
|
||||
io2();
|
||||
io();
|
||||
idle2();
|
||||
idle();
|
||||
aa.l = readDP(dp + r.x.w + 0);
|
||||
aa.h = readDP(dp + r.x.w + 1);
|
||||
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() {
|
||||
dp = readPC();
|
||||
io2();
|
||||
idle2();
|
||||
aa.l = readDP(dp + 0);
|
||||
aa.h = readDP(dp + 1);
|
||||
io();
|
||||
idle();
|
||||
L writeDB(aa.w + r.y.w, r.a.l);
|
||||
}
|
||||
|
||||
auto R65816::op_sta_idpy_w() {
|
||||
dp = readPC();
|
||||
io2();
|
||||
idle2();
|
||||
aa.l = readDP(dp + 0);
|
||||
aa.h = readDP(dp + 1);
|
||||
io();
|
||||
idle();
|
||||
writeDB(aa.w + r.y.w + 0, r.a.l);
|
||||
L writeDB(aa.w + r.y.w + 1, r.a.h);
|
||||
}
|
||||
|
||||
auto R65816::op_sta_ildpy_b() {
|
||||
dp = readPC();
|
||||
io2();
|
||||
idle2();
|
||||
aa.l = readDPn(dp + 0);
|
||||
aa.h = readDPn(dp + 1);
|
||||
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() {
|
||||
dp = readPC();
|
||||
io2();
|
||||
idle2();
|
||||
aa.l = readDPn(dp + 0);
|
||||
aa.h = readDPn(dp + 1);
|
||||
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() {
|
||||
sp = readPC();
|
||||
io();
|
||||
idle();
|
||||
L writeSP(sp, r.a.l);
|
||||
}
|
||||
|
||||
auto R65816::op_sta_sr_w() {
|
||||
sp = readPC();
|
||||
io();
|
||||
idle();
|
||||
writeSP(sp + 0, r.a.l);
|
||||
L writeSP(sp + 1, r.a.h);
|
||||
}
|
||||
|
||||
auto R65816::op_sta_isry_b() {
|
||||
sp = readPC();
|
||||
io();
|
||||
idle();
|
||||
aa.l = readSP(sp + 0);
|
||||
aa.h = readSP(sp + 1);
|
||||
io();
|
||||
idle();
|
||||
L writeDB(aa.w + r.y.w, r.a.l);
|
||||
}
|
||||
|
||||
auto R65816::op_sta_isry_w() {
|
||||
sp = readPC();
|
||||
io();
|
||||
idle();
|
||||
aa.l = readSP(sp + 0);
|
||||
aa.h = readSP(sp + 1);
|
||||
io();
|
||||
idle();
|
||||
writeDB(aa.w + r.y.w + 0, r.a.l);
|
||||
L writeDB(aa.w + r.y.w + 1, r.a.h);
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace Processor {
|
|||
#include "instructions-misc.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.
|
||||
//this affects the following opcodes:
|
||||
// clc, cld, cli, clv, sec, sed, sei,
|
||||
|
@ -27,36 +27,36 @@ namespace Processor {
|
|||
// tcd, tcs, tdc, tsc, tsx, txs,
|
||||
// inc, inx, iny, dec, dex, dey,
|
||||
// asl, lsr, rol, ror, nop, xce.
|
||||
auto R65816::ioIRQ() -> void {
|
||||
auto R65816::idleIRQ() -> void {
|
||||
if(interruptPending()) {
|
||||
//modify I/O cycle to bus read cycle, do not increment PC
|
||||
read(r.pc.d);
|
||||
} else {
|
||||
io();
|
||||
idle();
|
||||
}
|
||||
}
|
||||
|
||||
auto R65816::io2() -> void {
|
||||
auto R65816::idle2() -> void {
|
||||
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)) {
|
||||
io();
|
||||
idle();
|
||||
}
|
||||
}
|
||||
|
||||
auto R65816::io6(uint16 addr) -> void {
|
||||
auto R65816::idle6(uint16 addr) -> void {
|
||||
if(r.e && (r.pc.w & 0xff00) != (addr & 0xff00)) {
|
||||
io();
|
||||
idle();
|
||||
}
|
||||
}
|
||||
|
||||
auto R65816::interrupt() -> void {
|
||||
read(r.pc.d);
|
||||
io();
|
||||
idle();
|
||||
N writeSP(r.pc.b);
|
||||
writeSP(r.pc.h);
|
||||
writeSP(r.pc.l);
|
||||
|
|
|
@ -13,20 +13,20 @@ struct R65816 {
|
|||
|
||||
using fp = auto (R65816::*)() -> void;
|
||||
|
||||
virtual auto io() -> void = 0;
|
||||
virtual auto idle() -> void = 0;
|
||||
virtual auto read(uint24 addr) -> uint8 = 0;
|
||||
virtual auto write(uint24 addr, uint8 data) -> void = 0;
|
||||
virtual auto lastCycle() -> void = 0;
|
||||
virtual auto interruptPending() const -> bool = 0;
|
||||
virtual auto interrupt() -> void;
|
||||
|
||||
virtual auto readDisassembler(uint24 addr) -> uint8 { return 0; }
|
||||
|
||||
//r65816.cpp
|
||||
alwaysinline auto ioIRQ() -> void;
|
||||
alwaysinline auto io2() -> void;
|
||||
alwaysinline auto io4(uint16 x, uint16 y) -> void;
|
||||
alwaysinline auto io6(uint16 addr) -> void;
|
||||
alwaysinline auto idleIRQ() -> void;
|
||||
alwaysinline auto idle2() -> void;
|
||||
alwaysinline auto idle4(uint16 x, uint16 y) -> void;
|
||||
alwaysinline auto idle6(uint16 addr) -> void;
|
||||
auto interrupt() -> void;
|
||||
|
||||
//algorithms.cpp
|
||||
auto op_adc_b();
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#define call (this->*op)
|
||||
|
||||
auto SPC700::op_adjust(fps op, reg r) {
|
||||
io();
|
||||
idle();
|
||||
r = call(r);
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,7 @@ auto SPC700::op_adjust_dpw(int n) {
|
|||
|
||||
auto SPC700::op_adjust_dpx(fps op) {
|
||||
dp = readPC();
|
||||
io();
|
||||
idle();
|
||||
rd = readDP(dp + regs.x);
|
||||
rd = call(rd);
|
||||
writeDP(dp + regs.x, rd);
|
||||
|
@ -41,8 +41,8 @@ auto SPC700::op_adjust_dpx(fps op) {
|
|||
auto SPC700::op_branch(bool condition) {
|
||||
rd = readPC();
|
||||
if(!condition) return;
|
||||
io();
|
||||
io();
|
||||
idle();
|
||||
idle();
|
||||
regs.pc += (int8)rd;
|
||||
}
|
||||
|
||||
|
@ -50,22 +50,22 @@ auto SPC700::op_branch_bit() {
|
|||
dp = readPC();
|
||||
sp = readDP(dp);
|
||||
rd = readPC();
|
||||
io();
|
||||
idle();
|
||||
if((bool)(sp & (1 << (opcode >> 5))) == (bool)(opcode & 0x10)) return;
|
||||
io();
|
||||
io();
|
||||
idle();
|
||||
idle();
|
||||
regs.pc += (int8)rd;
|
||||
}
|
||||
|
||||
auto SPC700::op_pull(reg r) {
|
||||
io();
|
||||
io();
|
||||
idle();
|
||||
idle();
|
||||
r = readSP();
|
||||
}
|
||||
|
||||
auto SPC700::op_push(uint8 r) {
|
||||
io();
|
||||
io();
|
||||
idle();
|
||||
idle();
|
||||
writeSP(r);
|
||||
}
|
||||
|
||||
|
@ -79,7 +79,7 @@ auto SPC700::op_read_addr(fpb op, reg r) {
|
|||
auto SPC700::op_read_addri(fpb op, reg r) {
|
||||
dp.l = readPC();
|
||||
dp.h = readPC();
|
||||
io();
|
||||
idle();
|
||||
rd = read(dp + r);
|
||||
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) {
|
||||
dp = readPC();
|
||||
io();
|
||||
idle();
|
||||
rd = readDP(dp + i);
|
||||
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) {
|
||||
dp = readPC();
|
||||
rd.l = readDP(dp++);
|
||||
if(op != &SPC700::op_cpw) io();
|
||||
if(op != &SPC700::op_cpw) idle();
|
||||
rd.h = readDP(dp++);
|
||||
regs.ya = call(regs.ya, rd);
|
||||
}
|
||||
|
||||
auto SPC700::op_read_idpx(fpb op) {
|
||||
dp = readPC() + regs.x;
|
||||
io();
|
||||
idle();
|
||||
sp.l = readDP(dp++);
|
||||
sp.h = readDP(dp++);
|
||||
rd = read(sp);
|
||||
|
@ -121,7 +121,7 @@ auto SPC700::op_read_idpx(fpb op) {
|
|||
|
||||
auto SPC700::op_read_idpy(fpb op) {
|
||||
dp = readPC();
|
||||
io();
|
||||
idle();
|
||||
sp.l = readDP(dp++);
|
||||
sp.h = readDP(dp++);
|
||||
rd = read(sp + regs.y);
|
||||
|
@ -129,7 +129,7 @@ auto SPC700::op_read_idpy(fpb op) {
|
|||
}
|
||||
|
||||
auto SPC700::op_read_ix(fpb op) {
|
||||
io();
|
||||
idle();
|
||||
rd = readDP(regs.x);
|
||||
regs.a = call(regs.a, rd);
|
||||
}
|
||||
|
@ -143,7 +143,7 @@ auto SPC700::op_set_addr_bit() {
|
|||
switch(opcode >> 5) {
|
||||
case 0: //orc addr:bit
|
||||
case 1: //orc !addr:bit
|
||||
io();
|
||||
idle();
|
||||
regs.p.c |= (rd & (1 << bit)) ^ (bool)(opcode & 0x20);
|
||||
break;
|
||||
case 2: //and addr:bit
|
||||
|
@ -151,14 +151,14 @@ auto SPC700::op_set_addr_bit() {
|
|||
regs.p.c &= (rd & (1 << bit)) ^ (bool)(opcode & 0x20);
|
||||
break;
|
||||
case 4: //eor addr:bit
|
||||
io();
|
||||
idle();
|
||||
regs.p.c ^= (bool)(rd & (1 << bit));
|
||||
break;
|
||||
case 5: //ldc addr:bit
|
||||
regs.p.c = (rd & (1 << bit));
|
||||
break;
|
||||
case 6: //stc addr:bit
|
||||
io();
|
||||
idle();
|
||||
rd = (rd & ~(1 << bit)) | (regs.p.c << bit);
|
||||
write(dp, rd);
|
||||
break;
|
||||
|
@ -176,8 +176,8 @@ auto SPC700::op_set_bit() {
|
|||
}
|
||||
|
||||
auto SPC700::op_set_flag(uint bit, bool value) {
|
||||
io();
|
||||
if(bit == regs.p.i.bit) io();
|
||||
idle();
|
||||
if(bit == regs.p.i.bit) idle();
|
||||
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) {
|
||||
io();
|
||||
idle();
|
||||
to = from;
|
||||
if(&to == ®s.s) return;
|
||||
regs.p.n = (to & 0x80);
|
||||
|
@ -209,7 +209,7 @@ auto SPC700::op_write_addr(reg r) {
|
|||
auto SPC700::op_write_addri(reg i) {
|
||||
dp.l = readPC();
|
||||
dp.h = readPC();
|
||||
io();
|
||||
idle();
|
||||
dp += i;
|
||||
read(dp);
|
||||
write(dp, regs.a);
|
||||
|
@ -223,7 +223,7 @@ auto SPC700::op_write_dp(reg r) {
|
|||
|
||||
auto SPC700::op_write_dpi(reg r, reg i) {
|
||||
dp = readPC() + i;
|
||||
io();
|
||||
idle();
|
||||
readDP(dp);
|
||||
writeDP(dp, r);
|
||||
}
|
||||
|
@ -233,7 +233,7 @@ auto SPC700::op_write_dp_const(fpb op) {
|
|||
dp = readPC();
|
||||
wr = readDP(dp);
|
||||
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) {
|
||||
|
@ -242,15 +242,15 @@ auto SPC700::op_write_dp_dp(fpb op) {
|
|||
dp = readPC();
|
||||
if(op != &SPC700::op_st) wr = readDP(dp);
|
||||
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) {
|
||||
io();
|
||||
idle();
|
||||
rd = readDP(regs.y);
|
||||
wr = readDP(regs.x);
|
||||
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();
|
||||
sp = readDP(dp);
|
||||
rd = readPC();
|
||||
io();
|
||||
idle();
|
||||
if(regs.a == sp) return;
|
||||
io();
|
||||
io();
|
||||
idle();
|
||||
idle();
|
||||
regs.pc += (int8)rd;
|
||||
}
|
||||
|
||||
|
@ -272,38 +272,38 @@ auto SPC700::op_bne_dpdec() {
|
|||
writeDP(dp, --wr);
|
||||
rd = readPC();
|
||||
if(wr == 0) return;
|
||||
io();
|
||||
io();
|
||||
idle();
|
||||
idle();
|
||||
regs.pc += (int8)rd;
|
||||
}
|
||||
|
||||
auto SPC700::op_bne_dpx() {
|
||||
dp = readPC();
|
||||
io();
|
||||
idle();
|
||||
sp = readDP(dp + regs.x);
|
||||
rd = readPC();
|
||||
io();
|
||||
idle();
|
||||
if(regs.a == sp) return;
|
||||
io();
|
||||
io();
|
||||
idle();
|
||||
idle();
|
||||
regs.pc += (int8)rd;
|
||||
}
|
||||
|
||||
auto SPC700::op_bne_ydec() {
|
||||
rd = readPC();
|
||||
io();
|
||||
io();
|
||||
idle();
|
||||
idle();
|
||||
if(--regs.y == 0) return;
|
||||
io();
|
||||
io();
|
||||
idle();
|
||||
idle();
|
||||
regs.pc += (int8)rd;
|
||||
}
|
||||
|
||||
auto SPC700::op_brk() {
|
||||
rd.l = read(0xffde);
|
||||
rd.h = read(0xffdf);
|
||||
io();
|
||||
io();
|
||||
idle();
|
||||
idle();
|
||||
writeSP(regs.pc.h);
|
||||
writeSP(regs.pc.l);
|
||||
writeSP(regs.p);
|
||||
|
@ -313,20 +313,20 @@ auto SPC700::op_brk() {
|
|||
}
|
||||
|
||||
auto SPC700::op_clv() {
|
||||
io();
|
||||
idle();
|
||||
regs.p.v = 0;
|
||||
regs.p.h = 0;
|
||||
}
|
||||
|
||||
auto SPC700::op_cmc() {
|
||||
io();
|
||||
io();
|
||||
idle();
|
||||
idle();
|
||||
regs.p.c = !regs.p.c;
|
||||
}
|
||||
|
||||
auto SPC700::op_daa() {
|
||||
io();
|
||||
io();
|
||||
idle();
|
||||
idle();
|
||||
if(regs.p.c || (regs.a) > 0x99) {
|
||||
regs.a += 0x60;
|
||||
regs.p.c = 1;
|
||||
|
@ -339,8 +339,8 @@ auto SPC700::op_daa() {
|
|||
}
|
||||
|
||||
auto SPC700::op_das() {
|
||||
io();
|
||||
io();
|
||||
idle();
|
||||
idle();
|
||||
if(!regs.p.c || (regs.a) > 0x99) {
|
||||
regs.a -= 0x60;
|
||||
regs.p.c = 0;
|
||||
|
@ -353,17 +353,17 @@ auto SPC700::op_das() {
|
|||
}
|
||||
|
||||
auto SPC700::op_div_ya_x() {
|
||||
io();
|
||||
io();
|
||||
io();
|
||||
io();
|
||||
io();
|
||||
io();
|
||||
io();
|
||||
io();
|
||||
io();
|
||||
io();
|
||||
io();
|
||||
idle();
|
||||
idle();
|
||||
idle();
|
||||
idle();
|
||||
idle();
|
||||
idle();
|
||||
idle();
|
||||
idle();
|
||||
idle();
|
||||
idle();
|
||||
idle();
|
||||
ya = regs.ya;
|
||||
//overflow set if quotient >= 256
|
||||
regs.p.v = (regs.y >= regs.x);
|
||||
|
@ -392,7 +392,7 @@ auto SPC700::op_jmp_addr() {
|
|||
auto SPC700::op_jmp_iaddrx() {
|
||||
dp.l = readPC();
|
||||
dp.h = readPC();
|
||||
io();
|
||||
idle();
|
||||
dp += regs.x;
|
||||
rd.l = read(dp++);
|
||||
rd.h = read(dp++);
|
||||
|
@ -401,8 +401,8 @@ auto SPC700::op_jmp_iaddrx() {
|
|||
|
||||
auto SPC700::op_jsp_dp() {
|
||||
rd = readPC();
|
||||
io();
|
||||
io();
|
||||
idle();
|
||||
idle();
|
||||
writeSP(regs.pc.h);
|
||||
writeSP(regs.pc.l);
|
||||
regs.pc = 0xff00 | rd;
|
||||
|
@ -411,9 +411,9 @@ auto SPC700::op_jsp_dp() {
|
|||
auto SPC700::op_jsr_addr() {
|
||||
rd.l = readPC();
|
||||
rd.h = readPC();
|
||||
io();
|
||||
io();
|
||||
io();
|
||||
idle();
|
||||
idle();
|
||||
idle();
|
||||
writeSP(regs.pc.h);
|
||||
writeSP(regs.pc.l);
|
||||
regs.pc = rd;
|
||||
|
@ -423,31 +423,31 @@ auto SPC700::op_jst() {
|
|||
dp = 0xffde - ((opcode >> 4) << 1);
|
||||
rd.l = read(dp++);
|
||||
rd.h = read(dp++);
|
||||
io();
|
||||
io();
|
||||
io();
|
||||
idle();
|
||||
idle();
|
||||
idle();
|
||||
writeSP(regs.pc.h);
|
||||
writeSP(regs.pc.l);
|
||||
regs.pc = rd;
|
||||
}
|
||||
|
||||
auto SPC700::op_lda_ixinc() {
|
||||
io();
|
||||
idle();
|
||||
regs.a = readDP(regs.x++);
|
||||
io();
|
||||
idle();
|
||||
regs.p.n = regs.a & 0x80;
|
||||
regs.p.z = regs.a == 0;
|
||||
}
|
||||
|
||||
auto SPC700::op_mul_ya() {
|
||||
io();
|
||||
io();
|
||||
io();
|
||||
io();
|
||||
io();
|
||||
io();
|
||||
io();
|
||||
io();
|
||||
idle();
|
||||
idle();
|
||||
idle();
|
||||
idle();
|
||||
idle();
|
||||
idle();
|
||||
idle();
|
||||
idle();
|
||||
ya = regs.y * regs.a;
|
||||
regs.a = ya;
|
||||
regs.y = ya >> 8;
|
||||
|
@ -457,12 +457,12 @@ auto SPC700::op_mul_ya() {
|
|||
}
|
||||
|
||||
auto SPC700::op_nop() {
|
||||
io();
|
||||
idle();
|
||||
}
|
||||
|
||||
auto SPC700::op_plp() {
|
||||
io();
|
||||
io();
|
||||
idle();
|
||||
idle();
|
||||
regs.p = readSP();
|
||||
}
|
||||
|
||||
|
@ -470,22 +470,22 @@ auto SPC700::op_rti() {
|
|||
regs.p = readSP();
|
||||
rd.l = readSP();
|
||||
rd.h = readSP();
|
||||
io();
|
||||
io();
|
||||
idle();
|
||||
idle();
|
||||
regs.pc = rd;
|
||||
}
|
||||
|
||||
auto SPC700::op_rts() {
|
||||
rd.l = readSP();
|
||||
rd.h = readSP();
|
||||
io();
|
||||
io();
|
||||
idle();
|
||||
idle();
|
||||
regs.pc = rd;
|
||||
}
|
||||
|
||||
auto SPC700::op_sta_idpx() {
|
||||
sp = readPC() + regs.x;
|
||||
io();
|
||||
idle();
|
||||
dp.l = readDP(sp++);
|
||||
dp.h = readDP(sp++);
|
||||
read(dp);
|
||||
|
@ -496,21 +496,21 @@ auto SPC700::op_sta_idpy() {
|
|||
sp = readPC();
|
||||
dp.l = readDP(sp++);
|
||||
dp.h = readDP(sp++);
|
||||
io();
|
||||
idle();
|
||||
dp += regs.y;
|
||||
read(dp);
|
||||
write(dp, regs.a);
|
||||
}
|
||||
|
||||
auto SPC700::op_sta_ix() {
|
||||
io();
|
||||
idle();
|
||||
readDP(regs.x);
|
||||
writeDP(regs.x, regs.a);
|
||||
}
|
||||
|
||||
auto SPC700::op_sta_ixinc() {
|
||||
io();
|
||||
io();
|
||||
idle();
|
||||
idle();
|
||||
writeDP(regs.x++, regs.a);
|
||||
}
|
||||
|
||||
|
@ -523,16 +523,16 @@ auto SPC700::op_stw_dp() {
|
|||
|
||||
auto SPC700::op_wait() {
|
||||
while(true) {
|
||||
io();
|
||||
io();
|
||||
idle();
|
||||
idle();
|
||||
}
|
||||
}
|
||||
|
||||
auto SPC700::op_xcn() {
|
||||
io();
|
||||
io();
|
||||
io();
|
||||
io();
|
||||
idle();
|
||||
idle();
|
||||
idle();
|
||||
idle();
|
||||
regs.a = (regs.a >> 4) | (regs.a << 4);
|
||||
regs.p.n = regs.a & 0x80;
|
||||
regs.p.z = regs.a == 0;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
namespace Processor {
|
||||
|
||||
struct SPC700 {
|
||||
virtual auto io() -> void = 0;
|
||||
virtual auto idle() -> void = 0;
|
||||
virtual auto read(uint16 addr) -> uint8 = 0;
|
||||
virtual auto write(uint16 addr, uint8 data) -> void = 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
|
||||
auto V30MZ::disassemble(uint16 cs, uint16 ip, bool registers, bool bytes) -> string {
|
||||
string s;
|
||||
|
|
|
@ -108,7 +108,7 @@ auto SA1::vbrRead(uint24 addr, uint8 data) -> uint8 {
|
|||
//tick() == 2 clock ticks
|
||||
//note: bus conflict delays are not emulated at this time
|
||||
|
||||
auto SA1::io() -> void {
|
||||
auto SA1::idle() -> void {
|
||||
tick();
|
||||
}
|
||||
|
||||
|
|
|
@ -30,19 +30,6 @@ auto SA1::main() -> void {
|
|||
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 {
|
||||
if(mmio.sa1_nmi && !mmio.sa1_nmicl) {
|
||||
status.interruptPending = true;
|
||||
|
|
|
@ -3,7 +3,6 @@ struct SA1 : Processor::R65816, Cothread {
|
|||
static auto Enter() -> void;
|
||||
auto main() -> void;
|
||||
auto tick() -> void;
|
||||
auto interrupt() -> void override;
|
||||
|
||||
alwaysinline auto triggerIRQ() -> void;
|
||||
alwaysinline auto lastCycle() -> void override;
|
||||
|
@ -47,7 +46,7 @@ struct SA1 : Processor::R65816, Cothread {
|
|||
auto busWrite(uint24 addr, uint8 data) -> void;
|
||||
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 write(uint24 addr, uint8 data) -> void override;
|
||||
|
||||
|
|
|
@ -12,25 +12,13 @@ CPU cpu;
|
|||
#include "serialization.cpp"
|
||||
|
||||
auto CPU::interruptPending() const -> bool { return status.interruptPending; }
|
||||
auto CPU::pio() const -> uint8 { return status.pio; }
|
||||
auto CPU::joylatch() const -> bool { return status.joypadStrobeLatch; }
|
||||
auto CPU::pio() const -> uint8 { return io.pio; }
|
||||
auto CPU::joylatch() const -> bool { return io.joypadStrobeLatch; }
|
||||
|
||||
CPU::CPU() {
|
||||
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 {
|
||||
if(smp.clock < 0) co_switch(smp.thread);
|
||||
}
|
||||
|
@ -68,12 +56,12 @@ auto CPU::main() -> void {
|
|||
interrupt();
|
||||
} else if(status.resetPending) {
|
||||
status.resetPending = false;
|
||||
addClocks(132);
|
||||
step(132);
|
||||
r.vector = 0xfffc;
|
||||
interrupt();
|
||||
} else if(status.powerPending) {
|
||||
status.powerPending = false;
|
||||
addClocks(186);
|
||||
step(186);
|
||||
r.pc.l = bus.read(0xfffc, r.mdr);
|
||||
r.pc.h = bus.read(0xfffd, r.mdr);
|
||||
}
|
||||
|
@ -161,49 +149,47 @@ auto CPU::reset() -> void {
|
|||
r.vector = 0xfffc; //reset vector address
|
||||
|
||||
//$2140-217f
|
||||
for(auto& port : status.port) port = 0x00;
|
||||
for(auto& port : io.port) port = 0x00;
|
||||
|
||||
//$2181-$2183
|
||||
status.wramAddress = 0x000000;
|
||||
io.wramAddress = 0x000000;
|
||||
|
||||
//$4016-$4017
|
||||
status.joypadStrobeLatch = 0;
|
||||
status.joypad1_bits = ~0;
|
||||
status.joypad2_bits = ~0;
|
||||
io.joypadStrobeLatch = 0;
|
||||
|
||||
//$4200
|
||||
status.nmiEnabled = false;
|
||||
status.hirqEnabled = false;
|
||||
status.virqEnabled = false;
|
||||
status.autoJoypadPoll = false;
|
||||
io.nmiEnabled = false;
|
||||
io.hirqEnabled = false;
|
||||
io.virqEnabled = false;
|
||||
io.autoJoypadPoll = false;
|
||||
|
||||
//$4201
|
||||
status.pio = 0xff;
|
||||
io.pio = 0xff;
|
||||
|
||||
//$4202-$4203
|
||||
status.wrmpya = 0xff;
|
||||
status.wrmpyb = 0xff;
|
||||
io.wrmpya = 0xff;
|
||||
io.wrmpyb = 0xff;
|
||||
|
||||
//$4204-$4206
|
||||
status.wrdiva = 0xffff;
|
||||
status.wrdivb = 0xff;
|
||||
io.wrdiva = 0xffff;
|
||||
io.wrdivb = 0xff;
|
||||
|
||||
//$4207-$420a
|
||||
status.hirqPos = 0x01ff;
|
||||
status.virqPos = 0x01ff;
|
||||
io.hirqPos = 0x01ff;
|
||||
io.virqPos = 0x01ff;
|
||||
|
||||
//$420d
|
||||
status.romSpeed = 8;
|
||||
io.romSpeed = 8;
|
||||
|
||||
//$4214-$4217
|
||||
status.rddiv = 0x0000;
|
||||
status.rdmpy = 0x0000;
|
||||
io.rddiv = 0x0000;
|
||||
io.rdmpy = 0x0000;
|
||||
|
||||
//$4218-$421f
|
||||
status.joy1 = 0x0000;
|
||||
status.joy2 = 0x0000;
|
||||
status.joy3 = 0x0000;
|
||||
status.joy4 = 0x0000;
|
||||
io.joy1 = 0x0000;
|
||||
io.joy2 = 0x0000;
|
||||
io.joy3 = 0x0000;
|
||||
io.joy4 = 0x0000;
|
||||
|
||||
//ALU
|
||||
alu.mpyctr = 0;
|
||||
|
|
|
@ -5,14 +5,13 @@ struct CPU : Processor::R65816, Thread, PPUcounter {
|
|||
|
||||
CPU();
|
||||
|
||||
alwaysinline auto step(uint clocks) -> void;
|
||||
alwaysinline auto synchronizeSMP() -> void;
|
||||
auto synchronizeSMP() -> void;
|
||||
auto synchronizePPU() -> void;
|
||||
auto synchronizeCoprocessors() -> void;
|
||||
auto synchronizePeripherals() -> void;
|
||||
|
||||
auto portRead(uint2 port) const -> uint8;
|
||||
auto portWrite(uint2 port, uint8 data) -> void;
|
||||
auto readPort(uint2 port) const -> uint8;
|
||||
auto writePort(uint2 port, uint8 data) -> void;
|
||||
|
||||
static auto Enter() -> void;
|
||||
auto main() -> void;
|
||||
|
@ -21,7 +20,7 @@ struct CPU : Processor::R65816, Thread, PPUcounter {
|
|||
auto reset() -> void;
|
||||
|
||||
//dma.cpp
|
||||
auto dmaAddClocks(uint clocks) -> void;
|
||||
auto dmaStep(uint clocks) -> void;
|
||||
auto dmaTransferValid(uint8 bbus, uint24 abus) -> bool;
|
||||
auto dmaAddressValid(uint24 abus) -> bool;
|
||||
auto dmaRead(uint24 abus) -> uint8;
|
||||
|
@ -46,7 +45,7 @@ struct CPU : Processor::R65816, Thread, PPUcounter {
|
|||
auto hdmaInit() -> void;
|
||||
|
||||
//memory.cpp
|
||||
auto io() -> void override;
|
||||
auto idle() -> void override;
|
||||
auto read(uint24 addr) -> uint8 override;
|
||||
auto write(uint24 addr, uint8 data) -> void override;
|
||||
alwaysinline auto speed(uint24 addr) const -> uint;
|
||||
|
@ -63,7 +62,7 @@ struct CPU : Processor::R65816, Thread, PPUcounter {
|
|||
//timing.cpp
|
||||
auto dmaCounter() const -> uint;
|
||||
|
||||
auto addClocks(uint clocks) -> void;
|
||||
auto step(uint clocks) -> void;
|
||||
auto scanline() -> void;
|
||||
|
||||
alwaysinline auto aluEdge() -> void;
|
||||
|
@ -138,8 +137,9 @@ privileged:
|
|||
bool autoJoypadLatch;
|
||||
uint autoJoypadCounter;
|
||||
uint autoJoypadClock;
|
||||
} status;
|
||||
|
||||
//MMIO
|
||||
struct IO {
|
||||
//$2140-217f
|
||||
uint8 port[4];
|
||||
|
||||
|
@ -148,8 +148,6 @@ privileged:
|
|||
|
||||
//$4016-$4017
|
||||
bool joypadStrobeLatch;
|
||||
uint32 joypad1_bits;
|
||||
uint32 joypad2_bits;
|
||||
|
||||
//$4200
|
||||
bool nmiEnabled;
|
||||
|
@ -184,7 +182,7 @@ privileged:
|
|||
uint16 joy2;
|
||||
uint16 joy3;
|
||||
uint16 joy4;
|
||||
} status;
|
||||
} io;
|
||||
|
||||
struct ALU {
|
||||
uint mpyctr;
|
||||
|
@ -218,8 +216,8 @@ privileged:
|
|||
|
||||
//$43x5-$43x6
|
||||
union {
|
||||
uint16 transferSize = 0;
|
||||
uint16_t indirectAddress;
|
||||
uint16 transferSize;
|
||||
uint16 indirectAddress;
|
||||
};
|
||||
|
||||
//$43x7
|
||||
|
@ -237,6 +235,8 @@ privileged:
|
|||
//internal state
|
||||
bool hdmaCompleted;
|
||||
bool hdmaDoTransfer;
|
||||
|
||||
Channel() : transferSize(0) {}
|
||||
} channel[8];
|
||||
|
||||
struct Pipe {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
auto CPU::dmaAddClocks(uint clocks) -> void {
|
||||
auto CPU::dmaStep(uint clocks) -> void {
|
||||
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 {
|
||||
if(direction == 0) {
|
||||
dmaAddClocks(4);
|
||||
dmaStep(4);
|
||||
r.mdr = dmaRead(abus);
|
||||
dmaAddClocks(4);
|
||||
dmaStep(4);
|
||||
dmaWrite(dmaTransferValid(bbus, abus), 0x2100 | bbus, r.mdr);
|
||||
} else {
|
||||
dmaAddClocks(4);
|
||||
dmaStep(4);
|
||||
r.mdr = dmaTransferValid(bbus, abus) ? bus.read(0x2100 | bbus, r.mdr) : (uint8)0x00;
|
||||
dmaAddClocks(4);
|
||||
dmaStep(4);
|
||||
dmaWrite(dmaAddressValid(abus), abus, r.mdr);
|
||||
}
|
||||
}
|
||||
|
@ -131,7 +131,7 @@ auto CPU::hdmaActiveChannels() -> uint {
|
|||
//==============
|
||||
|
||||
auto CPU::dmaRun() -> void {
|
||||
dmaAddClocks(8);
|
||||
dmaStep(8);
|
||||
dmaWrite(false);
|
||||
dmaEdge();
|
||||
|
||||
|
@ -144,7 +144,7 @@ auto CPU::dmaRun() -> void {
|
|||
dmaEdge();
|
||||
} while(channel[n].dmaEnabled && --channel[n].transferSize);
|
||||
|
||||
dmaAddClocks(8);
|
||||
dmaStep(8);
|
||||
dmaWrite(false);
|
||||
dmaEdge();
|
||||
|
||||
|
@ -155,9 +155,9 @@ auto CPU::dmaRun() -> void {
|
|||
}
|
||||
|
||||
auto CPU::hdmaUpdate(uint n) -> void {
|
||||
dmaAddClocks(4);
|
||||
dmaStep(4);
|
||||
r.mdr = dmaRead(channel[n].sourceBank << 16 | channel[n].hdmaAddress);
|
||||
dmaAddClocks(4);
|
||||
dmaStep(4);
|
||||
dmaWrite(false);
|
||||
|
||||
if((channel[n].lineCounter & 0x7f) == 0) {
|
||||
|
@ -168,18 +168,18 @@ auto CPU::hdmaUpdate(uint n) -> void {
|
|||
channel[n].hdmaDoTransfer = !channel[n].hdmaCompleted;
|
||||
|
||||
if(channel[n].indirect) {
|
||||
dmaAddClocks(4);
|
||||
dmaStep(4);
|
||||
r.mdr = dmaRead(hdmaAddress(n));
|
||||
channel[n].indirectAddress = r.mdr << 8;
|
||||
dmaAddClocks(4);
|
||||
dmaStep(4);
|
||||
dmaWrite(false);
|
||||
|
||||
if(!channel[n].hdmaCompleted || hdmaActiveAfter(n)) {
|
||||
dmaAddClocks(4);
|
||||
dmaStep(4);
|
||||
r.mdr = dmaRead(hdmaAddress(n));
|
||||
channel[n].indirectAddress >>= 8;
|
||||
channel[n].indirectAddress |= r.mdr << 8;
|
||||
dmaAddClocks(4);
|
||||
dmaStep(4);
|
||||
dmaWrite(false);
|
||||
}
|
||||
}
|
||||
|
@ -187,7 +187,7 @@ auto CPU::hdmaUpdate(uint n) -> void {
|
|||
}
|
||||
|
||||
auto CPU::hdmaRun() -> void {
|
||||
dmaAddClocks(8);
|
||||
dmaStep(8);
|
||||
dmaWrite(false);
|
||||
|
||||
for(auto n : range(8)) {
|
||||
|
@ -223,7 +223,7 @@ auto CPU::hdmaInitReset() -> void {
|
|||
}
|
||||
|
||||
auto CPU::hdmaInit() -> void {
|
||||
dmaAddClocks(8);
|
||||
dmaStep(8);
|
||||
dmaWrite(false);
|
||||
|
||||
for(auto n : range(8)) {
|
||||
|
|
|
@ -8,7 +8,7 @@ auto CPU::readCPU(uint24 addr, uint8 data) -> uint8 {
|
|||
|
||||
//WMDATA
|
||||
case 0x2180: {
|
||||
return bus.read(0x7e0000 | status.wramAddress++, r.mdr);
|
||||
return bus.read(0x7e0000 | io.wramAddress++, r.mdr);
|
||||
}
|
||||
|
||||
//JOYSER0
|
||||
|
@ -65,37 +65,37 @@ auto CPU::readCPU(uint24 addr, uint8 data) -> uint8 {
|
|||
|
||||
//RDIO
|
||||
case 0x4213: {
|
||||
return status.pio;
|
||||
return io.pio;
|
||||
}
|
||||
|
||||
//RDDIVL
|
||||
case 0x4214: {
|
||||
return status.rddiv.byte(0);
|
||||
return io.rddiv.byte(0);
|
||||
}
|
||||
|
||||
//RDDIVH
|
||||
case 0x4215: {
|
||||
return status.rddiv.byte(1);
|
||||
return io.rddiv.byte(1);
|
||||
}
|
||||
|
||||
//RDMPYL
|
||||
case 0x4216: {
|
||||
return status.rdmpy.byte(0);
|
||||
return io.rdmpy.byte(0);
|
||||
}
|
||||
|
||||
//RDMPYH
|
||||
case 0x4217: {
|
||||
return status.rdmpy.byte(1);
|
||||
return io.rdmpy.byte(1);
|
||||
}
|
||||
|
||||
case 0x4218: return status.joy1.byte(0); //JOY1L
|
||||
case 0x4219: return status.joy1.byte(1); //JOY1H
|
||||
case 0x421a: return status.joy2.byte(0); //JOY2L
|
||||
case 0x421b: return status.joy2.byte(1); //JOY2H
|
||||
case 0x421c: return status.joy3.byte(0); //JOY3L
|
||||
case 0x421d: return status.joy3.byte(1); //JOY3H
|
||||
case 0x421e: return status.joy4.byte(0); //JOY4L
|
||||
case 0x421f: return status.joy4.byte(1); //JOY4H
|
||||
case 0x4218: return io.joy1.byte(0); //JOY1L
|
||||
case 0x4219: return io.joy1.byte(1); //JOY1H
|
||||
case 0x421a: return io.joy2.byte(0); //JOY2L
|
||||
case 0x421b: return io.joy2.byte(1); //JOY2H
|
||||
case 0x421c: return io.joy3.byte(0); //JOY3L
|
||||
case 0x421d: return io.joy3.byte(1); //JOY3H
|
||||
case 0x421e: return io.joy4.byte(0); //JOY4L
|
||||
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 {
|
||||
synchronizeSMP();
|
||||
return portWrite(addr.bits(0,1), data);
|
||||
return writePort(addr.bits(0,1), data);
|
||||
}
|
||||
|
||||
auto CPU::writeCPU(uint24 addr, uint8 data) -> void {
|
||||
|
@ -166,12 +166,12 @@ auto CPU::writeCPU(uint24 addr, uint8 data) -> void {
|
|||
|
||||
//WMDATA
|
||||
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 0x2182: status.wramAddress.bits( 8,15) = data; return; //WMADDM
|
||||
case 0x2183: status.wramAddress.bit (16 ) = data.bit(0); return; //WMADDH
|
||||
case 0x2181: io.wramAddress.bits( 0, 7) = data; return; //WMADDL
|
||||
case 0x2182: io.wramAddress.bits( 8,15) = data; return; //WMADDM
|
||||
case 0x2183: io.wramAddress.bit (16 ) = data.bit(0); return; //WMADDH
|
||||
|
||||
//JOYSER0
|
||||
case 0x4016: {
|
||||
|
@ -185,54 +185,54 @@ auto CPU::writeCPU(uint24 addr, uint8 data) -> void {
|
|||
|
||||
//NMITIMEN
|
||||
case 0x4200: {
|
||||
status.autoJoypadPoll = data.bit(0);
|
||||
io.autoJoypadPoll = data.bit(0);
|
||||
nmitimenUpdate(data);
|
||||
return;
|
||||
}
|
||||
|
||||
//WRIO
|
||||
case 0x4201: {
|
||||
if(status.pio.bit(7) && !data.bit(7)) ppu.latchCounters();
|
||||
status.pio = data;
|
||||
if(io.pio.bit(7) && !data.bit(7)) ppu.latchCounters();
|
||||
io.pio = data;
|
||||
return;
|
||||
}
|
||||
|
||||
//WRMPYA
|
||||
case 0x4202: status.wrmpya = data; return;
|
||||
case 0x4202: io.wrmpya = data; return;
|
||||
|
||||
//WRMPYB
|
||||
case 0x4203: {
|
||||
status.rdmpy = 0;
|
||||
io.rdmpy = 0;
|
||||
if(alu.mpyctr || alu.divctr) return;
|
||||
|
||||
status.wrmpyb = data;
|
||||
status.rddiv = (status.wrmpyb << 8) | status.wrmpya;
|
||||
io.wrmpyb = data;
|
||||
io.rddiv = (io.wrmpyb << 8) | io.wrmpya;
|
||||
|
||||
alu.mpyctr = 8; //perform multiplication over the next eight cycles
|
||||
alu.shift = status.wrmpyb;
|
||||
alu.shift = io.wrmpyb;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x4204: { status.wrdiva.byte(0) = data; return; } //WRDIVL
|
||||
case 0x4205: { status.wrdiva.byte(1) = data; return; } //WRDIVH
|
||||
case 0x4204: { io.wrdiva.byte(0) = data; return; } //WRDIVL
|
||||
case 0x4205: { io.wrdiva.byte(1) = data; return; } //WRDIVH
|
||||
|
||||
//WRDIVB
|
||||
case 0x4206: {
|
||||
status.rdmpy = status.wrdiva;
|
||||
io.rdmpy = io.wrdiva;
|
||||
if(alu.mpyctr || alu.divctr) return;
|
||||
|
||||
status.wrdivb = data;
|
||||
io.wrdivb = data;
|
||||
|
||||
alu.divctr = 16; //perform division over the next sixteen cycles
|
||||
alu.shift = status.wrdivb << 16;
|
||||
alu.shift = io.wrdivb << 16;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x4207: status.hirqPos.bits(0,7) = data; return; //HTIMEL
|
||||
case 0x4208: status.hirqPos.bit (8 ) = data.bit(0); return; //HTIMEH
|
||||
case 0x4207: io.hirqPos.bits(0,7) = data; return; //HTIMEL
|
||||
case 0x4208: io.hirqPos.bit (8 ) = data.bit(0); return; //HTIMEH
|
||||
|
||||
case 0x4209: status.virqPos.bits(0,7) = data; return; //VTIMEL
|
||||
case 0x420a: status.virqPos.bit (8 ) = data.bit(0); return; //VTIMEH
|
||||
case 0x4209: io.virqPos.bits(0,7) = data; return; //VTIMEL
|
||||
case 0x420a: io.virqPos.bit (8 ) = data.bit(0); return; //VTIMEH
|
||||
|
||||
//DMAEN
|
||||
case 0x420b: {
|
||||
|
@ -249,7 +249,7 @@ auto CPU::writeCPU(uint24 addr, uint8 data) -> void {
|
|||
|
||||
//MEMSEL
|
||||
case 0x420d: {
|
||||
status.romSpeed = data.bit(0) ? 6 : 8;
|
||||
io.romSpeed = data.bit(0) ? 6 : 8;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ auto CPU::pollInterrupts() -> void {
|
|||
//NMI hold
|
||||
if(status.nmiHold) {
|
||||
status.nmiHold = false;
|
||||
if(status.nmiEnabled) status.nmiTransition = true;
|
||||
if(io.nmiEnabled) status.nmiTransition = true;
|
||||
}
|
||||
|
||||
//NMI test
|
||||
|
@ -25,15 +25,15 @@ auto CPU::pollInterrupts() -> void {
|
|||
//IRQ hold
|
||||
status.irqHold = false;
|
||||
if(status.irqLine) {
|
||||
if(status.virqEnabled || status.hirqEnabled) status.irqTransition = true;
|
||||
if(io.virqEnabled || io.hirqEnabled) status.irqTransition = true;
|
||||
}
|
||||
|
||||
//IRQ test
|
||||
bool irqValid = status.virqEnabled || status.hirqEnabled;
|
||||
bool irqValid = io.virqEnabled || io.hirqEnabled;
|
||||
if(irqValid) {
|
||||
if((status.virqEnabled && vcounter(10) != (status.virqPos))
|
||||
|| (status.hirqEnabled && hcounter(10) != (status.hirqPos + 1) * 4)
|
||||
|| (status.virqPos && vcounter(6) == 0) //IRQs cannot trigger on last dot of field
|
||||
if((io.virqEnabled && vcounter(10) != (io.virqPos))
|
||||
|| (io.hirqEnabled && hcounter(10) != (io.hirqPos + 1) * 4)
|
||||
|| (io.virqPos && vcounter(6) == 0) //IRQs cannot trigger on last dot of field
|
||||
) irqValid = false;
|
||||
}
|
||||
if(!status.irqValid && irqValid) {
|
||||
|
@ -45,24 +45,24 @@ auto CPU::pollInterrupts() -> void {
|
|||
}
|
||||
|
||||
auto CPU::nmitimenUpdate(uint8 data) -> void {
|
||||
bool nmiEnabled = status.nmiEnabled;
|
||||
bool virqEnabled = status.virqEnabled;
|
||||
bool hirqEnabled = status.hirqEnabled;
|
||||
status.nmiEnabled = data & 0x80;
|
||||
status.virqEnabled = data & 0x20;
|
||||
status.hirqEnabled = data & 0x10;
|
||||
bool nmiEnabled = io.nmiEnabled;
|
||||
bool virqEnabled = io.virqEnabled;
|
||||
bool hirqEnabled = io.hirqEnabled;
|
||||
io.nmiEnabled = data & 0x80;
|
||||
io.virqEnabled = data & 0x20;
|
||||
io.hirqEnabled = data & 0x10;
|
||||
|
||||
//0->1 edge sensitive transition
|
||||
if(!nmiEnabled && status.nmiEnabled && status.nmiLine) {
|
||||
if(!nmiEnabled && io.nmiEnabled && status.nmiLine) {
|
||||
status.nmiTransition = true;
|
||||
}
|
||||
|
||||
//?->1 level sensitive transition
|
||||
if(status.virqEnabled && !status.hirqEnabled && status.irqLine) {
|
||||
if(io.virqEnabled && !io.hirqEnabled && status.irqLine) {
|
||||
status.irqTransition = true;
|
||||
}
|
||||
|
||||
if(!status.virqEnabled && !status.hirqEnabled) {
|
||||
if(!io.virqEnabled && !io.hirqEnabled) {
|
||||
status.irqLine = false;
|
||||
status.irqTransition = false;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
auto CPU::stepAutoJoypadPoll() -> void {
|
||||
if(vcounter() >= ppu.vdisp()) {
|
||||
//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;
|
||||
|
||||
if(status.autoJoypadActive && status.autoJoypadLatch) {
|
||||
|
@ -16,10 +16,10 @@ auto CPU::stepAutoJoypadPoll() -> void {
|
|||
uint2 port0 = SuperFamicom::peripherals.controllerPort1->data();
|
||||
uint2 port1 = SuperFamicom::peripherals.controllerPort2->data();
|
||||
|
||||
status.joy1 = status.joy1 << 1 | port0.bit(0);
|
||||
status.joy2 = status.joy2 << 1 | port1.bit(0);
|
||||
status.joy3 = status.joy3 << 1 | port0.bit(1);
|
||||
status.joy4 = status.joy4 << 1 | port1.bit(1);
|
||||
io.joy1 = io.joy1 << 1 | port0.bit(0);
|
||||
io.joy2 = io.joy2 << 1 | port1.bit(0);
|
||||
io.joy3 = io.joy3 << 1 | port0.bit(1);
|
||||
io.joy4 = io.joy4 << 1 | port1.bit(1);
|
||||
}
|
||||
|
||||
status.autoJoypadCounter++;
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
auto CPU::portRead(uint2 port) const -> uint8 {
|
||||
return status.port[port];
|
||||
auto CPU::readPort(uint2 port) const -> uint8 {
|
||||
return io.port[port];
|
||||
}
|
||||
|
||||
auto CPU::portWrite(uint2 port, uint8 data) -> void {
|
||||
status.port[port] = data;
|
||||
auto CPU::writePort(uint2 port, uint8 data) -> void {
|
||||
io.port[port] = data;
|
||||
}
|
||||
|
||||
auto CPU::io() -> void {
|
||||
auto CPU::idle() -> void {
|
||||
status.clockCount = 6;
|
||||
dmaEdge();
|
||||
addClocks(6);
|
||||
step(6);
|
||||
aluEdge();
|
||||
}
|
||||
|
||||
auto CPU::read(uint24 addr) -> uint8 {
|
||||
status.clockCount = speed(addr);
|
||||
dmaEdge();
|
||||
addClocks(status.clockCount - 4);
|
||||
step(status.clockCount - 4);
|
||||
r.mdr = bus.read(addr, r.mdr);
|
||||
addClocks(4);
|
||||
step(4);
|
||||
aluEdge();
|
||||
return r.mdr;
|
||||
}
|
||||
|
@ -27,15 +27,12 @@ auto CPU::write(uint24 addr, uint8 data) -> void {
|
|||
aluEdge();
|
||||
status.clockCount = speed(addr);
|
||||
dmaEdge();
|
||||
addClocks(status.clockCount);
|
||||
step(status.clockCount);
|
||||
bus.write(addr, r.mdr = data);
|
||||
}
|
||||
|
||||
auto CPU::speed(uint24 addr) const -> uint {
|
||||
if(addr & 0x408000) {
|
||||
if(addr & 0x800000) return status.romSpeed;
|
||||
return 8;
|
||||
}
|
||||
if(addr & 0x408000) return addr & 0x800000 ? io.romSpeed : 8;
|
||||
if((addr + 0x6000) & 0x4000) return 8;
|
||||
if((addr - 0x4000) & 0x7e00) return 6;
|
||||
return 12;
|
||||
|
|
|
@ -50,39 +50,37 @@ auto CPU::serialize(serializer& s) -> void {
|
|||
s.integer(status.autoJoypadCounter);
|
||||
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(status.joypad1_bits);
|
||||
s.integer(status.joypad2_bits);
|
||||
s.integer(io.joypadStrobeLatch);
|
||||
|
||||
s.integer(status.nmiEnabled);
|
||||
s.integer(status.hirqEnabled);
|
||||
s.integer(status.virqEnabled);
|
||||
s.integer(status.autoJoypadPoll);
|
||||
s.integer(io.nmiEnabled);
|
||||
s.integer(io.hirqEnabled);
|
||||
s.integer(io.virqEnabled);
|
||||
s.integer(io.autoJoypadPoll);
|
||||
|
||||
s.integer(status.pio);
|
||||
s.integer(io.pio);
|
||||
|
||||
s.integer(status.wrmpya);
|
||||
s.integer(status.wrmpyb);
|
||||
s.integer(io.wrmpya);
|
||||
s.integer(io.wrmpyb);
|
||||
|
||||
s.integer(status.wrdiva);
|
||||
s.integer(status.wrdivb);
|
||||
s.integer(io.wrdiva);
|
||||
s.integer(io.wrdivb);
|
||||
|
||||
s.integer(status.hirqPos);
|
||||
s.integer(status.virqPos);
|
||||
s.integer(io.hirqPos);
|
||||
s.integer(io.virqPos);
|
||||
|
||||
s.integer(status.romSpeed);
|
||||
s.integer(io.romSpeed);
|
||||
|
||||
s.integer(status.rddiv);
|
||||
s.integer(status.rdmpy);
|
||||
s.integer(io.rddiv);
|
||||
s.integer(io.rdmpy);
|
||||
|
||||
s.integer(status.joy1);
|
||||
s.integer(status.joy2);
|
||||
s.integer(status.joy3);
|
||||
s.integer(status.joy4);
|
||||
s.integer(io.joy1);
|
||||
s.integer(io.joy2);
|
||||
s.integer(io.joy3);
|
||||
s.integer(io.joy4);
|
||||
|
||||
s.integer(alu.mpyctr);
|
||||
s.integer(alu.divctr);
|
||||
|
|
|
@ -2,7 +2,7 @@ auto CPU::dmaCounter() const -> uint {
|
|||
return (status.dmaCounter + hcounter()) & 7;
|
||||
}
|
||||
|
||||
auto CPU::addClocks(uint clocks) -> void {
|
||||
auto CPU::step(uint clocks) -> void {
|
||||
status.irqLock = false;
|
||||
uint ticks = clocks >> 1;
|
||||
while(ticks--) {
|
||||
|
@ -10,7 +10,15 @@ auto CPU::addClocks(uint clocks) -> void {
|
|||
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;
|
||||
if(status.autoJoypadClock >= 256) {
|
||||
|
@ -20,7 +28,7 @@ auto CPU::addClocks(uint clocks) -> void {
|
|||
|
||||
if(!status.dramRefreshed && hcounter() >= status.dramRefreshPosition) {
|
||||
status.dramRefreshed = true;
|
||||
addClocks(40);
|
||||
step(40);
|
||||
}
|
||||
|
||||
#if defined(DEBUGGER)
|
||||
|
@ -62,18 +70,18 @@ auto CPU::scanline() -> void {
|
|||
auto CPU::aluEdge() -> void {
|
||||
if(alu.mpyctr) {
|
||||
alu.mpyctr--;
|
||||
if(status.rddiv & 1) status.rdmpy += alu.shift;
|
||||
status.rddiv >>= 1;
|
||||
if(io.rddiv & 1) io.rdmpy += alu.shift;
|
||||
io.rddiv >>= 1;
|
||||
alu.shift <<= 1;
|
||||
}
|
||||
|
||||
if(alu.divctr) {
|
||||
alu.divctr--;
|
||||
status.rddiv <<= 1;
|
||||
io.rddiv <<= 1;
|
||||
alu.shift >>= 1;
|
||||
if(status.rdmpy >= alu.shift) {
|
||||
status.rdmpy -= alu.shift;
|
||||
status.rddiv |= 1;
|
||||
if(io.rdmpy >= alu.shift) {
|
||||
io.rdmpy -= alu.shift;
|
||||
io.rddiv |= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -92,11 +100,11 @@ auto CPU::dmaEdge() -> void {
|
|||
status.hdmaPending = false;
|
||||
if(hdmaEnabledChannels()) {
|
||||
if(!dmaEnabledChannels()) {
|
||||
dmaAddClocks(8 - dmaCounter());
|
||||
dmaStep(8 - dmaCounter());
|
||||
}
|
||||
status.hdmaMode == 0 ? hdmaInit() : hdmaRun();
|
||||
if(!dmaEnabledChannels()) {
|
||||
addClocks(status.clockCount - (status.dmaClocks % status.clockCount));
|
||||
step(status.clockCount - (status.dmaClocks % status.clockCount));
|
||||
status.dmaActive = false;
|
||||
}
|
||||
}
|
||||
|
@ -105,9 +113,9 @@ auto CPU::dmaEdge() -> void {
|
|||
if(status.dmaPending) {
|
||||
status.dmaPending = false;
|
||||
if(dmaEnabledChannels()) {
|
||||
dmaAddClocks(8 - dmaCounter());
|
||||
dmaStep(8 - dmaCounter());
|
||||
dmaRun();
|
||||
addClocks(status.clockCount - (status.dmaClocks % status.clockCount));
|
||||
step(status.clockCount - (status.dmaClocks % status.clockCount));
|
||||
status.dmaActive = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -244,8 +244,8 @@ auto Interface::cheatSet(const lstring& list) -> void {
|
|||
lstring codes = codeset.split("+");
|
||||
for(auto& code : codes) {
|
||||
lstring part = code.split("/");
|
||||
if(part.size() == 2) GameBoy::cheat.append(hex(part[0]), hex(part[1]));
|
||||
if(part.size() == 3) GameBoy::cheat.append(hex(part[0]), hex(part[1]), hex(part[2]));
|
||||
if(part.size() == 2) GameBoy::cheat.append(part[0].hex(), part[1].hex());
|
||||
if(part.size() == 3) GameBoy::cheat.append(part[0].hex(), part[1].hex(), part[2].hex());
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
@ -256,8 +256,8 @@ auto Interface::cheatSet(const lstring& list) -> void {
|
|||
lstring codes = codeset.split("+");
|
||||
for(auto& code : codes) {
|
||||
lstring part = code.split("/");
|
||||
if(part.size() == 2) cheat.append(hex(part[0]), hex(part[1]));
|
||||
if(part.size() == 3) cheat.append(hex(part[0]), hex(part[1]), hex(part[2]));
|
||||
if(part.size() == 2) cheat.append(part[0].hex(), part[1].hex());
|
||||
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]) {
|
||||
if(++id >= 256) return print("SFC error: bus map exhausted\n");
|
||||
}
|
||||
//print("map[", hex(id, 2), "] => ", addr, "\n");
|
||||
|
||||
reader[id] = read;
|
||||
writer[id] = write;
|
||||
|
@ -47,10 +46,10 @@ auto Bus::map(
|
|||
for(auto& addr : addrs) {
|
||||
auto bankRange = bank.split("-", 1L);
|
||||
auto addrRange = addr.split("-", 1L);
|
||||
uint bankLo = hex(bankRange(0));
|
||||
uint bankHi = hex(bankRange(1, bankRange(0)));
|
||||
uint addrLo = hex(addrRange(0));
|
||||
uint addrHi = hex(addrRange(1, addrRange(0)));
|
||||
uint bankLo = bankRange(0).hex();
|
||||
uint bankHi = bankRange(1, bankRange(0)).hex();
|
||||
uint addrLo = addrRange(0).hex();
|
||||
uint addrHi = addrRange(1, addrRange(0)).hex();
|
||||
|
||||
for(uint bank = bankLo; bank <= bankHi; bank++) {
|
||||
for(uint addr = addrLo; addr <= addrHi; addr++) {
|
||||
|
@ -79,10 +78,10 @@ auto Bus::unmap(const string& addr) -> void {
|
|||
for(auto& addr : addrs) {
|
||||
auto bankRange = bank.split("-", 1L);
|
||||
auto addrRange = addr.split("-", 1L);
|
||||
uint bankLo = hex(bankRange(0));
|
||||
uint bankHi = hex(bankRange(1, bankRange(0)));
|
||||
uint addrLo = hex(addrRange(0));
|
||||
uint addrHi = hex(addrRange(1, addrRange(1)));
|
||||
uint bankLo = bankRange(0).hex();
|
||||
uint bankHi = bankRange(1, bankRange(0)).hex();
|
||||
uint addrLo = addrRange(0).hex();
|
||||
uint addrHi = addrRange(1, addrRange(1)).hex();
|
||||
|
||||
for(uint bank = bankLo; bank <= bankHi; bank++) {
|
||||
for(uint addr = addrLo; addr <= addrHi; addr++) {
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
#include "mode7.cpp"
|
||||
|
||||
auto PPU::Background::voffset() const -> uint16 {
|
||||
if(r.mosaic) return latch.voffset;
|
||||
return r.voffset;
|
||||
if(io.mosaic) return latch.voffset;
|
||||
return io.voffset;
|
||||
}
|
||||
|
||||
auto PPU::Background::hoffset() const -> uint16 {
|
||||
if(r.mosaic) return latch.hoffset;
|
||||
return r.hoffset;
|
||||
if(io.mosaic) return latch.hoffset;
|
||||
return io.hoffset;
|
||||
}
|
||||
|
||||
//V = 0, H = 0
|
||||
|
@ -20,70 +20,70 @@ auto PPU::Background::scanline() -> void {
|
|||
|
||||
//H = 28
|
||||
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;
|
||||
y = ppu.vcounter();
|
||||
|
||||
if(y == 1) {
|
||||
mosaic.vcounter = r.mosaic + 1;
|
||||
mosaic.vcounter = io.mosaic + 1;
|
||||
mosaic.voffset = 1;
|
||||
latch.hoffset = r.hoffset;
|
||||
latch.voffset = r.voffset;
|
||||
latch.hoffset = io.hoffset;
|
||||
latch.voffset = io.voffset;
|
||||
} else if(--mosaic.vcounter == 0) {
|
||||
mosaic.vcounter = r.mosaic + 1;
|
||||
mosaic.voffset += r.mosaic + 1;
|
||||
latch.hoffset = r.hoffset;
|
||||
latch.voffset = r.voffset;
|
||||
mosaic.vcounter = io.mosaic + 1;
|
||||
mosaic.voffset += io.mosaic + 1;
|
||||
latch.hoffset = io.hoffset;
|
||||
latch.voffset = io.voffset;
|
||||
}
|
||||
|
||||
tileCounter = (7 - (latch.hoffset & 7)) << hires;
|
||||
for(auto& d : data) d = 0;
|
||||
|
||||
mosaic.hcounter = r.mosaic + 1;
|
||||
mosaic.hcounter = io.mosaic + 1;
|
||||
mosaic.hoffset = 0;
|
||||
|
||||
if(r.mode == Mode::Mode7) return beginMode7();
|
||||
if(r.mosaic == 0) {
|
||||
latch.hoffset = r.hoffset;
|
||||
latch.voffset = r.voffset;
|
||||
if(io.mode == Mode::Mode7) return beginMode7();
|
||||
if(io.mosaic == 0) {
|
||||
latch.hoffset = io.hoffset;
|
||||
latch.voffset = io.voffset;
|
||||
}
|
||||
}
|
||||
|
||||
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 paletteOffset = (ppu.r.bgMode == 0 ? id << 5 : 0);
|
||||
uint colorDepth = (io.mode == Mode::BPP2 ? 0 : io.mode == Mode::BPP4 ? 1 : 2);
|
||||
uint paletteOffset = (ppu.io.bgMode == 0 ? id << 5 : 0);
|
||||
uint paletteSize = 2 << 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 width = 256 << hires;
|
||||
|
||||
uint hmask = (tileHeight == 3 ? width : width << 1);
|
||||
uint vmask = hmask;
|
||||
if(r.screenSize & 1) hmask <<= 1;
|
||||
if(r.screenSize & 2) vmask <<= 1;
|
||||
if(io.screenSize & 1) hmask <<= 1;
|
||||
if(io.screenSize & 2) vmask <<= 1;
|
||||
hmask--;
|
||||
vmask--;
|
||||
|
||||
uint px = x << hires;
|
||||
uint py = (r.mosaic == 0 ? y : mosaic.voffset);
|
||||
uint py = (io.mosaic == 0 ? y : mosaic.voffset);
|
||||
|
||||
uint hscroll = hoffset();
|
||||
uint vscroll = voffset();
|
||||
if(hires) {
|
||||
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 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));
|
||||
|
||||
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 validMask = (id == ID::BG1 ? 0x2000 : 0x4000);
|
||||
|
||||
if(ppu.r.bgMode == 4) {
|
||||
if(ppu.io.bgMode == 4) {
|
||||
if(hval & validMask) {
|
||||
if((hval & 0x8000) == 0) {
|
||||
hoffset = offsetX + (hval & ~7);
|
||||
|
@ -109,9 +109,9 @@ auto PPU::Background::getTile() -> void {
|
|||
hoffset &= hmask;
|
||||
voffset &= vmask;
|
||||
|
||||
uint screenX = (r.screenSize & 1 ? 32 << 5 : 0);
|
||||
uint screenY = (r.screenSize & 2 ? 32 << 5 : 0);
|
||||
if(r.screenSize == 3) screenY <<= 1;
|
||||
uint screenX = (io.screenSize & 1 ? 32 << 5 : 0);
|
||||
uint screenY = (io.screenSize & 2 ? 32 << 5 : 0);
|
||||
if(io.screenSize == 3) screenY <<= 1;
|
||||
|
||||
uint tx = hoffset >> tileWidth;
|
||||
uint ty = voffset >> tileHeight;
|
||||
|
@ -120,11 +120,11 @@ auto PPU::Background::getTile() -> void {
|
|||
if(tx & 0x20) offset += screenX;
|
||||
if(ty & 0x20) offset += screenY;
|
||||
|
||||
uint16 address = r.screenAddress + offset;
|
||||
uint16 address = io.screenAddress + offset;
|
||||
tile = ppu.vram[address];
|
||||
bool mirrorY = tile & 0x8000;
|
||||
bool mirrorX = tile & 0x4000;
|
||||
priority = r.priority[bool(tile & 0x2000)];
|
||||
priority = io.priority[bool(tile & 0x2000)];
|
||||
paletteNumber = (tile >> 10) & 7;
|
||||
paletteIndex = paletteOffset + (paletteNumber << paletteSize);
|
||||
|
||||
|
@ -135,7 +135,7 @@ auto PPU::Background::getTile() -> void {
|
|||
if(mirrorY) voffset ^= 7;
|
||||
offset = (character << (3 + colorDepth)) + (voffset & 7);
|
||||
|
||||
switch(r.mode) {
|
||||
switch(io.mode) {
|
||||
case Mode::BPP8:
|
||||
data[1].bits(16,31) = ppu.vram[offset + 24];
|
||||
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 {
|
||||
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) {
|
||||
output.above.priority = 0;
|
||||
|
@ -167,12 +167,12 @@ auto PPU::Background::run(bool screen) -> void {
|
|||
getTile();
|
||||
}
|
||||
|
||||
if(r.mode == Mode::Mode7) return runMode7();
|
||||
if(io.mode == Mode::Mode7) return runMode7();
|
||||
|
||||
uint8 palette = getTileColor();
|
||||
if(x == 0) mosaic.hcounter = 1;
|
||||
if(x >= 0 && --mosaic.hcounter == 0) {
|
||||
mosaic.hcounter = r.mosaic + 1;
|
||||
mosaic.hcounter = io.mosaic + 1;
|
||||
mosaic.priority = priority;
|
||||
mosaic.palette = palette ? paletteIndex + palette : 0;
|
||||
mosaic.tile = tile;
|
||||
|
@ -180,14 +180,14 @@ auto PPU::Background::run(bool screen) -> void {
|
|||
if(screen == Screen::Above) x++;
|
||||
if(mosaic.palette == 0) return;
|
||||
|
||||
if(!hires || screen == Screen::Above) if(r.aboveEnable) output.above = mosaic;
|
||||
if(!hires || screen == Screen::Below) if(r.belowEnable) output.below = mosaic;
|
||||
if(!hires || screen == Screen::Above) if(io.aboveEnable) output.above = mosaic;
|
||||
if(!hires || screen == Screen::Below) if(io.belowEnable) output.below = mosaic;
|
||||
}
|
||||
|
||||
auto PPU::Background::getTileColor() -> uint {
|
||||
uint color = 0;
|
||||
|
||||
switch(r.mode) {
|
||||
switch(io.mode) {
|
||||
case Mode::BPP8:
|
||||
color += data[1] >> 24 & 0x80;
|
||||
color += data[1] >> 17 & 0x40;
|
||||
|
@ -207,17 +207,17 @@ auto PPU::Background::getTileColor() -> uint {
|
|||
}
|
||||
|
||||
auto PPU::Background::reset() -> void {
|
||||
r.tiledataAddress = (random(0x0000) & 0x0f) << 12;
|
||||
r.screenAddress = (random(0x0000) & 0xfc) << 8;
|
||||
r.screenSize = random(0);
|
||||
r.mosaic = random(0);
|
||||
r.tileSize = random(0);
|
||||
r.mode = 0;
|
||||
for(auto& p : r.priority) p = 0;
|
||||
r.aboveEnable = random(0);
|
||||
r.belowEnable = random(0);
|
||||
r.hoffset = random(0x0000);
|
||||
r.voffset = random(0x0000);
|
||||
io.tiledataAddress = (random(0x0000) & 0x0f) << 12;
|
||||
io.screenAddress = (random(0x0000) & 0xfc) << 8;
|
||||
io.screenSize = random(0);
|
||||
io.mosaic = random(0);
|
||||
io.tileSize = random(0);
|
||||
io.mode = 0;
|
||||
for(auto& p : io.priority) p = 0;
|
||||
io.aboveEnable = random(0);
|
||||
io.belowEnable = random(0);
|
||||
io.hoffset = random(0x0000);
|
||||
io.voffset = random(0x0000);
|
||||
|
||||
latch.hoffset = 0;
|
||||
latch.voffset = 0;
|
||||
|
@ -248,20 +248,20 @@ auto PPU::Background::reset() -> void {
|
|||
}
|
||||
|
||||
auto PPU::Background::getTile(uint x, uint y) -> uint {
|
||||
bool hires = (ppu.r.bgMode == 5 || ppu.r.bgMode == 6);
|
||||
uint tileHeight = (r.tileSize == TileSize::Size8x8 ? 3 : 4);
|
||||
bool hires = (ppu.io.bgMode == 5 || ppu.io.bgMode == 6);
|
||||
uint tileHeight = (io.tileSize == TileSize::Size8x8 ? 3 : 4);
|
||||
uint tileWidth = (!hires ? tileHeight : 4);
|
||||
uint width = (!hires ? 256 : 512);
|
||||
uint maskX = (tileHeight == 3 ? width : width << 1);
|
||||
uint maskY = maskX;
|
||||
if(r.screenSize & 1) maskX <<= 1;
|
||||
if(r.screenSize & 2) maskY <<= 1;
|
||||
if(io.screenSize & 1) maskX <<= 1;
|
||||
if(io.screenSize & 2) maskY <<= 1;
|
||||
maskX--;
|
||||
maskY--;
|
||||
|
||||
uint screenX = (r.screenSize & 1 ? 32 << 5 : 0);
|
||||
uint screenY = (r.screenSize & 2 ? 32 << 5 : 0);
|
||||
if(r.screenSize == 3) screenY <<= 1;
|
||||
uint screenX = (io.screenSize & 1 ? 32 << 5 : 0);
|
||||
uint screenY = (io.screenSize & 2 ? 32 << 5 : 0);
|
||||
if(io.screenSize == 3) screenY <<= 1;
|
||||
|
||||
x = (x & maskX) >> tileWidth;
|
||||
y = (y & maskY) >> tileHeight;
|
||||
|
@ -270,6 +270,6 @@ auto PPU::Background::getTile(uint x, uint y) -> uint {
|
|||
if(x & 0x20) offset += screenX;
|
||||
if(y & 0x20) offset += screenY;
|
||||
|
||||
uint16 address = r.screenAddress + offset;
|
||||
uint16 address = io.screenAddress + offset;
|
||||
return ppu.vram[address];
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ struct Background {
|
|||
struct TileSize { enum : uint { Size8x8, Size16x16 }; };
|
||||
struct Screen { enum : uint { Above, Below }; };
|
||||
|
||||
struct Registers {
|
||||
struct IO {
|
||||
uint16 tiledataAddress;
|
||||
uint16 screenAddress;
|
||||
uint2 screenSize;
|
||||
|
@ -42,7 +42,7 @@ struct Background {
|
|||
|
||||
uint16 hoffset;
|
||||
uint16 voffset;
|
||||
} r;
|
||||
} io;
|
||||
|
||||
struct Latch {
|
||||
uint16 hoffset;
|
||||
|
|
|
@ -5,18 +5,18 @@ auto PPU::Background::clip(int n) -> int {
|
|||
|
||||
//H = 28
|
||||
auto PPU::Background::beginMode7() -> void {
|
||||
latch.hoffset = ppu.r.hoffsetMode7;
|
||||
latch.voffset = ppu.r.voffsetMode7;
|
||||
latch.hoffset = ppu.io.hoffsetMode7;
|
||||
latch.voffset = ppu.io.voffsetMode7;
|
||||
}
|
||||
|
||||
auto PPU::Background::runMode7() -> void {
|
||||
int a = (int16)ppu.r.m7a;
|
||||
int b = (int16)ppu.r.m7b;
|
||||
int c = (int16)ppu.r.m7c;
|
||||
int d = (int16)ppu.r.m7d;
|
||||
int a = (int16)ppu.io.m7a;
|
||||
int b = (int16)ppu.io.m7b;
|
||||
int c = (int16)ppu.io.m7c;
|
||||
int d = (int16)ppu.io.m7d;
|
||||
|
||||
int cx = (int13)ppu.r.m7x;
|
||||
int cy = (int13)ppu.r.m7y;
|
||||
int cx = (int13)ppu.io.m7x;
|
||||
int cy = (int13)ppu.io.m7y;
|
||||
int hoffset = (int13)latch.hoffset;
|
||||
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
|
||||
|
||||
if(--mosaic.hcounter == 0) {
|
||||
mosaic.hcounter = r.mosaic + 1;
|
||||
mosaic.hoffset += r.mosaic + 1;
|
||||
mosaic.hcounter = io.mosaic + 1;
|
||||
mosaic.hoffset += io.mosaic + 1;
|
||||
}
|
||||
|
||||
if(ppu.r.hflipMode7) x = 255 - x;
|
||||
if(ppu.r.vflipMode7) y = 255 - y;
|
||||
if(ppu.io.hflipMode7) x = 255 - x;
|
||||
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 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 palette;
|
||||
switch(ppu.r.repeatMode7) {
|
||||
switch(ppu.io.repeatMode7) {
|
||||
//screen repetition outside of screen area
|
||||
case 0:
|
||||
case 1:
|
||||
|
@ -81,21 +81,21 @@ auto PPU::Background::runMode7() -> void {
|
|||
|
||||
uint priority;
|
||||
if(id == ID::BG1) {
|
||||
priority = r.priority[0];
|
||||
priority = io.priority[0];
|
||||
} else if(id == ID::BG2) {
|
||||
priority = r.priority[bool(palette & 0x80)];
|
||||
priority = io.priority[bool(palette & 0x80)];
|
||||
palette &= 0x7f;
|
||||
}
|
||||
|
||||
if(palette == 0) return;
|
||||
|
||||
if(r.aboveEnable) {
|
||||
if(io.aboveEnable) {
|
||||
output.above.palette = palette;
|
||||
output.above.priority = priority;
|
||||
output.above.tile = 0;
|
||||
}
|
||||
|
||||
if(r.belowEnable) {
|
||||
if(io.belowEnable) {
|
||||
output.below.palette = palette;
|
||||
output.below.priority = priority;
|
||||
output.below.tile = 0;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
auto PPU::getVramAddress() -> uint16 {
|
||||
uint16 address = r.vramAddress;
|
||||
switch(r.vramMapping) {
|
||||
uint16 address = io.vramAddress;
|
||||
switch(io.vramMapping) {
|
||||
case 0: return (address);
|
||||
case 1: return (address & 0xff00) | ((address & 0x001f) << 3) | ((address >> 5) & 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 {
|
||||
return r.displayDisable || vcounter() >= vdisp();
|
||||
return io.displayDisable || vcounter() >= vdisp();
|
||||
}
|
||||
|
||||
auto PPU::oamWrite(uint addr, uint8 data) -> void {
|
||||
oam[addr] = data;
|
||||
obj.update(addr, data);
|
||||
obj.oam.write(addr, data);
|
||||
}
|
||||
|
||||
auto PPU::readIO(uint24 addr, uint8 data) -> uint8 {
|
||||
|
@ -33,21 +32,21 @@ auto PPU::readIO(uint24 addr, uint8 data) -> uint8 {
|
|||
|
||||
//MPYL
|
||||
case 0x2134: {
|
||||
uint result = (int16)r.m7a * (int8)(r.m7b >> 8);
|
||||
uint result = (int16)io.m7a * (int8)(io.m7b >> 8);
|
||||
ppu1.mdr = (result >> 0);
|
||||
return ppu1.mdr;
|
||||
}
|
||||
|
||||
//MPYM
|
||||
case 0x2135: {
|
||||
uint result = (int16)r.m7a * (int8)(r.m7b >> 8);
|
||||
uint result = (int16)io.m7a * (int8)(io.m7b >> 8);
|
||||
ppu1.mdr = (result >> 8);
|
||||
return ppu1.mdr;
|
||||
}
|
||||
|
||||
//MPYH
|
||||
case 0x2136: {
|
||||
uint result = (int16)r.m7a * (int8)(r.m7b >> 8);
|
||||
uint result = (int16)io.m7a * (int8)(io.m7b >> 8);
|
||||
ppu1.mdr = (result >> 16);
|
||||
return ppu1.mdr;
|
||||
}
|
||||
|
@ -55,16 +54,16 @@ auto PPU::readIO(uint24 addr, uint8 data) -> uint8 {
|
|||
//SLHV
|
||||
case 0x2137: {
|
||||
if(cpu.pio() & 0x80) latchCounters();
|
||||
return cpu.r.mdr;
|
||||
return data; //CPU MDR
|
||||
}
|
||||
|
||||
//OAMDATAREAD
|
||||
case 0x2138: {
|
||||
uint10 address = r.oamAddress++;
|
||||
if(!r.displayDisable && vcounter() < vdisp()) address = latch.oamAddress;
|
||||
uint10 address = io.oamAddress++;
|
||||
if(!io.displayDisable && vcounter() < vdisp()) address = latch.oamAddress;
|
||||
if(address & 0x0200) address &= 0x021f;
|
||||
|
||||
ppu1.mdr = oam[address];
|
||||
ppu1.mdr = obj.oam.read(address);
|
||||
obj.setFirstSprite();
|
||||
return ppu1.mdr;
|
||||
}
|
||||
|
@ -72,9 +71,9 @@ auto PPU::readIO(uint24 addr, uint8 data) -> uint8 {
|
|||
//VMDATALREAD
|
||||
case 0x2139: {
|
||||
ppu1.mdr = latch.vram >> 0;
|
||||
if(r.vramIncrementMode == 0) {
|
||||
if(io.vramIncrementMode == 0) {
|
||||
latch.vram = vramAccessible() ? vram[getVramAddress()] : (uint16)0;
|
||||
r.vramAddress += r.vramIncrementSize;
|
||||
io.vramAddress += io.vramIncrementSize;
|
||||
}
|
||||
return ppu1.mdr;
|
||||
}
|
||||
|
@ -82,26 +81,26 @@ auto PPU::readIO(uint24 addr, uint8 data) -> uint8 {
|
|||
//VMDATAHREAD
|
||||
case 0x213a: {
|
||||
ppu1.mdr = latch.vram >> 8;
|
||||
if(r.vramIncrementMode == 1) {
|
||||
if(io.vramIncrementMode == 1) {
|
||||
latch.vram = vramAccessible() ? vram[getVramAddress()] : (uint16)0;
|
||||
r.vramAddress += r.vramIncrementSize;
|
||||
io.vramAddress += io.vramIncrementSize;
|
||||
}
|
||||
return ppu1.mdr;
|
||||
}
|
||||
|
||||
//CGDATAREAD
|
||||
case 0x213b: {
|
||||
auto address = r.cgramAddress;
|
||||
if(!r.displayDisable
|
||||
auto address = io.cgramAddress;
|
||||
if(!io.displayDisable
|
||||
&& vcounter() > 0 && vcounter() < vdisp()
|
||||
&& hcounter() >= 88 && hcounter() < 1096
|
||||
) address = latch.cgramAddress;
|
||||
|
||||
if(r.cgramAddressLatch++) {
|
||||
ppu2.mdr = cgram[address].byte(0);
|
||||
if(io.cgramAddressLatch++) {
|
||||
ppu2.mdr = screen.cgram[address].byte(0);
|
||||
} else {
|
||||
ppu2.mdr &= 0x80;
|
||||
ppu2.mdr |= cgram[address].byte(1);
|
||||
ppu2.mdr |= screen.cgram[address].byte(1);
|
||||
}
|
||||
return ppu2.mdr;
|
||||
}
|
||||
|
@ -109,10 +108,10 @@ auto PPU::readIO(uint24 addr, uint8 data) -> uint8 {
|
|||
//OPHCT
|
||||
case 0x213c: {
|
||||
if(latch.hcounter == 0) {
|
||||
ppu2.mdr = (r.hcounter >> 0);
|
||||
ppu2.mdr = (io.hcounter >> 0);
|
||||
} else {
|
||||
ppu2.mdr &= 0xfe;
|
||||
ppu2.mdr |= (r.hcounter >> 8) & 1;
|
||||
ppu2.mdr |= (io.hcounter >> 8) & 1;
|
||||
}
|
||||
latch.hcounter ^= 1;
|
||||
return ppu2.mdr;
|
||||
|
@ -121,10 +120,10 @@ auto PPU::readIO(uint24 addr, uint8 data) -> uint8 {
|
|||
//OPVCT
|
||||
case 0x213d: {
|
||||
if(latch.vcounter == 0) {
|
||||
ppu2.mdr = (r.vcounter >> 0);
|
||||
ppu2.mdr = (io.vcounter >> 0);
|
||||
} else {
|
||||
ppu2.mdr &= 0xfe;
|
||||
ppu2.mdr |= (r.vcounter >> 8) & 1;
|
||||
ppu2.mdr |= (io.vcounter >> 8) & 1;
|
||||
}
|
||||
latch.vcounter ^= 1;
|
||||
return ppu2.mdr;
|
||||
|
@ -133,8 +132,8 @@ auto PPU::readIO(uint24 addr, uint8 data) -> uint8 {
|
|||
//STAT77
|
||||
case 0x213e: {
|
||||
ppu1.mdr &= 0x10;
|
||||
ppu1.mdr |= obj.r.timeOver << 7;
|
||||
ppu1.mdr |= obj.r.rangeOver << 6;
|
||||
ppu1.mdr |= obj.io.timeOver << 7;
|
||||
ppu1.mdr |= obj.io.rangeOver << 6;
|
||||
ppu1.mdr |= ppu1.version & 0x0f;
|
||||
return ppu1.mdr;
|
||||
}
|
||||
|
@ -169,40 +168,40 @@ auto PPU::writeIO(uint24 addr, uint8 data) -> void {
|
|||
|
||||
//INIDISP
|
||||
case 0x2100: {
|
||||
if(r.displayDisable && vcounter() == vdisp()) obj.addressReset();
|
||||
r.displayBrightness = data.bits(0,3);
|
||||
r.displayDisable = data.bit (7);
|
||||
if(io.displayDisable && vcounter() == vdisp()) obj.addressReset();
|
||||
io.displayBrightness = data.bits(0,3);
|
||||
io.displayDisable = data.bit (7);
|
||||
return;
|
||||
}
|
||||
|
||||
//OBSEL
|
||||
case 0x2101: {
|
||||
obj.r.tiledataAddress = data.bits(0,2) << 13;
|
||||
obj.r.nameSelect = data.bits(3,4);
|
||||
obj.r.baseSize = data.bits(5,7);
|
||||
obj.io.tiledataAddress = data.bits(0,2) << 13;
|
||||
obj.io.nameselect = data.bits(3,4);
|
||||
obj.io.baseSize = data.bits(5,7);
|
||||
return;
|
||||
}
|
||||
|
||||
//OAMADDL
|
||||
case 0x2102: {
|
||||
r.oamBaseAddress = (r.oamBaseAddress & 0x0200) | (data << 1);
|
||||
io.oamBaseAddress = (io.oamBaseAddress & 0x0200) | (data << 1);
|
||||
obj.addressReset();
|
||||
return;
|
||||
}
|
||||
|
||||
//OAMADDH
|
||||
case 0x2103: {
|
||||
r.oamPriority = data & 0x80;
|
||||
r.oamBaseAddress = ((data & 0x01) << 9) | (r.oamBaseAddress & 0x01fe);
|
||||
io.oamPriority = data & 0x80;
|
||||
io.oamBaseAddress = ((data & 0x01) << 9) | (io.oamBaseAddress & 0x01fe);
|
||||
obj.addressReset();
|
||||
return;
|
||||
}
|
||||
|
||||
//OAMDATA
|
||||
case 0x2104: {
|
||||
bool l = r.oamAddress & 1;
|
||||
uint10 address = r.oamAddress++;
|
||||
if(!r.displayDisable && vcounter() < vdisp()) address = latch.oamAddress;
|
||||
bool l = io.oamAddress & 1;
|
||||
uint10 address = io.oamAddress++;
|
||||
if(!io.displayDisable && vcounter() < vdisp()) address = latch.oamAddress;
|
||||
if(address & 0x0200) address &= 0x021f;
|
||||
|
||||
if(l == 0) latch.oam = data;
|
||||
|
@ -218,12 +217,12 @@ auto PPU::writeIO(uint24 addr, uint8 data) -> void {
|
|||
|
||||
//BGMODE
|
||||
case 0x2105: {
|
||||
r.bgMode = data.bits(0,2);
|
||||
r.bgPriority = data.bit (3);
|
||||
bg1.r.tileSize = data.bit (4);
|
||||
bg2.r.tileSize = data.bit (5);
|
||||
bg3.r.tileSize = data.bit (6);
|
||||
bg4.r.tileSize = data.bit (7);
|
||||
io.bgMode = data.bits(0,2);
|
||||
io.bgPriority = data.bit (3);
|
||||
bg1.io.tileSize = data.bit (4);
|
||||
bg2.io.tileSize = data.bit (5);
|
||||
bg3.io.tileSize = data.bit (6);
|
||||
bg4.io.tileSize = data.bit (7);
|
||||
updateVideoMode();
|
||||
return;
|
||||
}
|
||||
|
@ -231,140 +230,136 @@ auto PPU::writeIO(uint24 addr, uint8 data) -> void {
|
|||
//MOSAIC
|
||||
case 0x2106: {
|
||||
uint mosaicSize = data.bits(4,7);
|
||||
bg1.r.mosaic = data.bit(0) ? mosaicSize : 0;
|
||||
bg2.r.mosaic = data.bit(1) ? mosaicSize : 0;
|
||||
bg3.r.mosaic = data.bit(2) ? mosaicSize : 0;
|
||||
bg4.r.mosaic = data.bit(3) ? mosaicSize : 0;
|
||||
bg1.io.mosaic = data.bit(0) ? mosaicSize : 0;
|
||||
bg2.io.mosaic = data.bit(1) ? mosaicSize : 0;
|
||||
bg3.io.mosaic = data.bit(2) ? mosaicSize : 0;
|
||||
bg4.io.mosaic = data.bit(3) ? mosaicSize : 0;
|
||||
return;
|
||||
}
|
||||
|
||||
//BG1SC
|
||||
case 0x2107: {
|
||||
bg1.r.screenSize = data.bits(0,1);
|
||||
bg1.r.screenAddress = data.bits(2,7) << 10;
|
||||
bg1.io.screenSize = data.bits(0,1);
|
||||
bg1.io.screenAddress = data.bits(2,7) << 10;
|
||||
return;
|
||||
}
|
||||
|
||||
//BG2SC
|
||||
case 0x2108: {
|
||||
bg2.r.screenSize = data.bits(0,1);
|
||||
bg2.r.screenAddress = data.bits(2,7) << 10;
|
||||
bg2.io.screenSize = data.bits(0,1);
|
||||
bg2.io.screenAddress = data.bits(2,7) << 10;
|
||||
return;
|
||||
}
|
||||
|
||||
//BG3SC
|
||||
case 0x2109: {
|
||||
bg3.r.screenSize = data.bits(0,1);
|
||||
bg3.r.screenAddress = data.bits(2,7) << 10;
|
||||
bg3.io.screenSize = data.bits(0,1);
|
||||
bg3.io.screenAddress = data.bits(2,7) << 10;
|
||||
return;
|
||||
}
|
||||
|
||||
//BG4SC
|
||||
case 0x210a: {
|
||||
bg4.r.screenSize = data.bits(0,1);
|
||||
bg4.r.screenAddress = data.bits(2,7) << 10;
|
||||
bg4.io.screenSize = data.bits(0,1);
|
||||
bg4.io.screenAddress = data.bits(2,7) << 10;
|
||||
return;
|
||||
}
|
||||
|
||||
//BG12NBA
|
||||
case 0x210b: {
|
||||
bg1.r.tiledataAddress = data.bits(0,3) << 12;
|
||||
bg2.r.tiledataAddress = data.bits(4,7) << 12;
|
||||
bg1.io.tiledataAddress = data.bits(0,3) << 12;
|
||||
bg2.io.tiledataAddress = data.bits(4,7) << 12;
|
||||
return;
|
||||
}
|
||||
|
||||
//BG34NBA
|
||||
case 0x210c: {
|
||||
bg3.r.tiledataAddress = data.bits(0,3) << 12;
|
||||
bg4.r.tiledataAddress = data.bits(4,7) << 12;
|
||||
bg3.io.tiledataAddress = data.bits(0,3) << 12;
|
||||
bg4.io.tiledataAddress = data.bits(4,7) << 12;
|
||||
return;
|
||||
}
|
||||
|
||||
//BG1HOFS
|
||||
case 0x210d: {
|
||||
r.hoffsetMode7 = (data << 8) | latch.mode7;
|
||||
io.hoffsetMode7 = (data << 8) | latch.mode7;
|
||||
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;
|
||||
return;
|
||||
}
|
||||
|
||||
//BG1VOFS
|
||||
case 0x210e: {
|
||||
r.voffsetMode7 = (data << 8) | latch.mode7;
|
||||
io.voffsetMode7 = (data << 8) | latch.mode7;
|
||||
latch.mode7 = data;
|
||||
|
||||
bg1.r.voffset = (data << 8) | latch.bgofs;
|
||||
bg1.io.voffset = (data << 8) | latch.bgofs;
|
||||
latch.bgofs = data;
|
||||
return;
|
||||
}
|
||||
|
||||
//BG2HOFS
|
||||
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;
|
||||
return;
|
||||
}
|
||||
|
||||
//BG2VOFS
|
||||
case 0x2110: {
|
||||
bg2.r.voffset = (data << 8) | latch.bgofs;
|
||||
bg2.io.voffset = (data << 8) | latch.bgofs;
|
||||
latch.bgofs = data;
|
||||
return;
|
||||
}
|
||||
|
||||
//BG3HOFS
|
||||
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;
|
||||
return;
|
||||
}
|
||||
|
||||
//BG3VOFS
|
||||
case 0x2112: {
|
||||
bg3.r.voffset = (data << 8) | latch.bgofs;
|
||||
bg3.io.voffset = (data << 8) | latch.bgofs;
|
||||
latch.bgofs = data;
|
||||
return;
|
||||
}
|
||||
|
||||
//BG4HOFS
|
||||
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;
|
||||
return;
|
||||
}
|
||||
|
||||
//BG4VOFS
|
||||
case 0x2114: {
|
||||
bg4.r.voffset = (data << 8) | latch.bgofs;
|
||||
bg4.io.voffset = (data << 8) | latch.bgofs;
|
||||
latch.bgofs = data;
|
||||
return;
|
||||
}
|
||||
|
||||
//VMAIN
|
||||
case 0x2115: {
|
||||
r.vramIncrementMode = data & 0x80;
|
||||
r.vramMapping = (data >> 2) & 3;
|
||||
switch(data & 3) {
|
||||
case 0: r.vramIncrementSize = 1; break;
|
||||
case 1: r.vramIncrementSize = 32; break;
|
||||
case 2: r.vramIncrementSize = 128; break;
|
||||
case 3: r.vramIncrementSize = 128; break;
|
||||
}
|
||||
static const uint size[4] = {1, 32, 128, 128};
|
||||
io.vramIncrementSize = size[data.bits(0,1)];
|
||||
io.vramMapping = data.bits(2,3);
|
||||
io.vramIncrementMode = data.bit (7);
|
||||
return;
|
||||
}
|
||||
|
||||
//VMADDL
|
||||
case 0x2116: {
|
||||
r.vramAddress.byte(0) = data;
|
||||
io.vramAddress.byte(0) = data;
|
||||
latch.vram = vramAccessible() ? vram[getVramAddress()] : (uint16)0;
|
||||
return;
|
||||
}
|
||||
|
||||
//VMADDH
|
||||
case 0x2117: {
|
||||
r.vramAddress.byte(1) = data;
|
||||
io.vramAddress.byte(1) = data;
|
||||
latch.vram = vramAccessible() ? vram[getVramAddress()] : (uint16)0;
|
||||
return;
|
||||
}
|
||||
|
@ -372,247 +367,247 @@ auto PPU::writeIO(uint24 addr, uint8 data) -> void {
|
|||
//VMDATAL
|
||||
case 0x2118: {
|
||||
if(vramAccessible()) vram[getVramAddress()].byte(0) = data;
|
||||
if(r.vramIncrementMode == 0) r.vramAddress += r.vramIncrementSize;
|
||||
if(io.vramIncrementMode == 0) io.vramAddress += io.vramIncrementSize;
|
||||
return;
|
||||
}
|
||||
|
||||
//VMDATAH
|
||||
case 0x2119: {
|
||||
if(vramAccessible()) vram[getVramAddress()].byte(1) = data;
|
||||
if(r.vramIncrementMode == 1) r.vramAddress += r.vramIncrementSize;
|
||||
if(io.vramIncrementMode == 1) io.vramAddress += io.vramIncrementSize;
|
||||
return;
|
||||
}
|
||||
|
||||
//M7SEL
|
||||
case 0x211a: {
|
||||
r.hflipMode7 = data.bit (0);
|
||||
r.vflipMode7 = data.bit (1);
|
||||
r.repeatMode7 = data.bits(6,7);
|
||||
io.hflipMode7 = data.bit (0);
|
||||
io.vflipMode7 = data.bit (1);
|
||||
io.repeatMode7 = data.bits(6,7);
|
||||
return;
|
||||
}
|
||||
|
||||
//M7A
|
||||
case 0x211b: {
|
||||
r.m7a = data << 8 | latch.mode7;
|
||||
io.m7a = data << 8 | latch.mode7;
|
||||
latch.mode7 = data;
|
||||
return;
|
||||
}
|
||||
|
||||
//M7B
|
||||
case 0x211c: {
|
||||
r.m7b = data << 8 | latch.mode7;
|
||||
io.m7b = data << 8 | latch.mode7;
|
||||
latch.mode7 = data;
|
||||
return;
|
||||
}
|
||||
|
||||
//M7C
|
||||
case 0x211d: {
|
||||
r.m7c = data << 8 | latch.mode7;
|
||||
io.m7c = data << 8 | latch.mode7;
|
||||
latch.mode7 = data;
|
||||
return;
|
||||
}
|
||||
|
||||
//M7D
|
||||
case 0x211e: {
|
||||
r.m7d = data << 8 | latch.mode7;
|
||||
io.m7d = data << 8 | latch.mode7;
|
||||
latch.mode7 = data;
|
||||
return;
|
||||
}
|
||||
|
||||
//M7X
|
||||
case 0x211f: {
|
||||
r.m7x = data << 8 | latch.mode7;
|
||||
io.m7x = data << 8 | latch.mode7;
|
||||
latch.mode7 = data;
|
||||
return;
|
||||
}
|
||||
|
||||
//M7Y
|
||||
case 0x2120: {
|
||||
r.m7y = data << 8 | latch.mode7;
|
||||
io.m7y = data << 8 | latch.mode7;
|
||||
latch.mode7 = data;
|
||||
return;
|
||||
}
|
||||
|
||||
//CGADD
|
||||
case 0x2121: {
|
||||
r.cgramAddress = data;
|
||||
r.cgramAddressLatch = 0;
|
||||
io.cgramAddress = data;
|
||||
io.cgramAddressLatch = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
//CGDATA
|
||||
case 0x2122: {
|
||||
auto address = r.cgramAddress;
|
||||
if(!r.displayDisable
|
||||
auto address = io.cgramAddress;
|
||||
if(!io.displayDisable
|
||||
&& vcounter() > 0 && vcounter() < vdisp()
|
||||
&& hcounter() >= 88 && hcounter() < 1096
|
||||
) address = latch.cgramAddress;
|
||||
|
||||
if(r.cgramAddressLatch++ == 0) {
|
||||
if(io.cgramAddressLatch++ == 0) {
|
||||
latch.cgram = data;
|
||||
} else {
|
||||
cgram[address] = data.bits(0,6) << 8 | latch.cgram;
|
||||
r.cgramAddress++;
|
||||
screen.cgram[address] = data.bits(0,6) << 8 | latch.cgram;
|
||||
io.cgramAddress++;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//W12SEL
|
||||
case 0x2123: {
|
||||
window.r.bg1.oneInvert = data.bit(0);
|
||||
window.r.bg1.oneEnable = data.bit(1);
|
||||
window.r.bg1.twoInvert = data.bit(2);
|
||||
window.r.bg1.twoEnable = data.bit(3);
|
||||
window.r.bg2.oneInvert = data.bit(4);
|
||||
window.r.bg2.oneEnable = data.bit(5);
|
||||
window.r.bg2.twoInvert = data.bit(6);
|
||||
window.r.bg2.twoEnable = data.bit(7);
|
||||
window.io.bg1.oneInvert = data.bit(0);
|
||||
window.io.bg1.oneEnable = data.bit(1);
|
||||
window.io.bg1.twoInvert = data.bit(2);
|
||||
window.io.bg1.twoEnable = data.bit(3);
|
||||
window.io.bg2.oneInvert = data.bit(4);
|
||||
window.io.bg2.oneEnable = data.bit(5);
|
||||
window.io.bg2.twoInvert = data.bit(6);
|
||||
window.io.bg2.twoEnable = data.bit(7);
|
||||
return;
|
||||
}
|
||||
|
||||
//W34SEL
|
||||
case 0x2124: {
|
||||
window.r.bg3.oneInvert = data.bit(0);
|
||||
window.r.bg3.oneEnable = data.bit(1);
|
||||
window.r.bg3.twoInvert = data.bit(2);
|
||||
window.r.bg3.twoEnable = data.bit(3);
|
||||
window.r.bg4.oneInvert = data.bit(4);
|
||||
window.r.bg4.oneEnable = data.bit(5);
|
||||
window.r.bg4.twoInvert = data.bit(6);
|
||||
window.r.bg4.twoEnable = data.bit(7);
|
||||
window.io.bg3.oneInvert = data.bit(0);
|
||||
window.io.bg3.oneEnable = data.bit(1);
|
||||
window.io.bg3.twoInvert = data.bit(2);
|
||||
window.io.bg3.twoEnable = data.bit(3);
|
||||
window.io.bg4.oneInvert = data.bit(4);
|
||||
window.io.bg4.oneEnable = data.bit(5);
|
||||
window.io.bg4.twoInvert = data.bit(6);
|
||||
window.io.bg4.twoEnable = data.bit(7);
|
||||
return;
|
||||
}
|
||||
|
||||
//WOBJSEL
|
||||
case 0x2125: {
|
||||
window.r.obj.oneInvert = data.bit(0);
|
||||
window.r.obj.oneEnable = data.bit(1);
|
||||
window.r.obj.twoInvert = data.bit(2);
|
||||
window.r.obj.twoEnable = data.bit(3);
|
||||
window.r.col.oneInvert = data.bit(4);
|
||||
window.r.col.oneEnable = data.bit(5);
|
||||
window.r.col.twoInvert = data.bit(6);
|
||||
window.r.col.twoEnable = data.bit(7);
|
||||
window.io.obj.oneInvert = data.bit(0);
|
||||
window.io.obj.oneEnable = data.bit(1);
|
||||
window.io.obj.twoInvert = data.bit(2);
|
||||
window.io.obj.twoEnable = data.bit(3);
|
||||
window.io.col.oneInvert = data.bit(4);
|
||||
window.io.col.oneEnable = data.bit(5);
|
||||
window.io.col.twoInvert = data.bit(6);
|
||||
window.io.col.twoEnable = data.bit(7);
|
||||
return;
|
||||
}
|
||||
|
||||
//WH0
|
||||
case 0x2126: {
|
||||
window.r.oneLeft = data;
|
||||
window.io.oneLeft = data;
|
||||
return;
|
||||
}
|
||||
|
||||
//WH1
|
||||
case 0x2127: {
|
||||
window.r.oneRight = data;
|
||||
window.io.oneRight = data;
|
||||
return;
|
||||
}
|
||||
|
||||
//WH2
|
||||
case 0x2128: {
|
||||
window.r.twoLeft = data;
|
||||
window.io.twoLeft = data;
|
||||
return;
|
||||
}
|
||||
|
||||
//WH3
|
||||
case 0x2129: {
|
||||
window.r.twoRight = data;
|
||||
window.io.twoRight = data;
|
||||
return;
|
||||
}
|
||||
|
||||
//WBGLOG
|
||||
case 0x212a: {
|
||||
window.r.bg1.mask = data.bits(0,1);
|
||||
window.r.bg2.mask = data.bits(2,3);
|
||||
window.r.bg3.mask = data.bits(4,5);
|
||||
window.r.bg4.mask = data.bits(6,7);
|
||||
window.io.bg1.mask = data.bits(0,1);
|
||||
window.io.bg2.mask = data.bits(2,3);
|
||||
window.io.bg3.mask = data.bits(4,5);
|
||||
window.io.bg4.mask = data.bits(6,7);
|
||||
return;
|
||||
}
|
||||
|
||||
//WOBJLOG
|
||||
case 0x212b: {
|
||||
window.r.obj.mask = data.bits(0,1);
|
||||
window.r.col.mask = data.bits(2,3);
|
||||
window.io.obj.mask = data.bits(0,1);
|
||||
window.io.col.mask = data.bits(2,3);
|
||||
return;
|
||||
}
|
||||
|
||||
//TM
|
||||
case 0x212c: {
|
||||
bg1.r.aboveEnable = data.bit(0);
|
||||
bg2.r.aboveEnable = data.bit(1);
|
||||
bg3.r.aboveEnable = data.bit(2);
|
||||
bg4.r.aboveEnable = data.bit(3);
|
||||
obj.r.aboveEnable = data.bit(4);
|
||||
bg1.io.aboveEnable = data.bit(0);
|
||||
bg2.io.aboveEnable = data.bit(1);
|
||||
bg3.io.aboveEnable = data.bit(2);
|
||||
bg4.io.aboveEnable = data.bit(3);
|
||||
obj.io.aboveEnable = data.bit(4);
|
||||
return;
|
||||
}
|
||||
|
||||
//TS
|
||||
case 0x212d: {
|
||||
bg1.r.belowEnable = data.bit(0);
|
||||
bg2.r.belowEnable = data.bit(1);
|
||||
bg3.r.belowEnable = data.bit(2);
|
||||
bg4.r.belowEnable = data.bit(3);
|
||||
obj.r.belowEnable = data.bit(4);
|
||||
bg1.io.belowEnable = data.bit(0);
|
||||
bg2.io.belowEnable = data.bit(1);
|
||||
bg3.io.belowEnable = data.bit(2);
|
||||
bg4.io.belowEnable = data.bit(3);
|
||||
obj.io.belowEnable = data.bit(4);
|
||||
return;
|
||||
}
|
||||
|
||||
//TMW
|
||||
case 0x212e: {
|
||||
window.r.bg1.aboveEnable = data.bit(0);
|
||||
window.r.bg2.aboveEnable = data.bit(1);
|
||||
window.r.bg3.aboveEnable = data.bit(2);
|
||||
window.r.bg4.aboveEnable = data.bit(3);
|
||||
window.r.obj.aboveEnable = data.bit(4);
|
||||
window.io.bg1.aboveEnable = data.bit(0);
|
||||
window.io.bg2.aboveEnable = data.bit(1);
|
||||
window.io.bg3.aboveEnable = data.bit(2);
|
||||
window.io.bg4.aboveEnable = data.bit(3);
|
||||
window.io.obj.aboveEnable = data.bit(4);
|
||||
return;
|
||||
}
|
||||
|
||||
//TSW
|
||||
case 0x212f: {
|
||||
window.r.bg1.belowEnable = data.bit(0);
|
||||
window.r.bg2.belowEnable = data.bit(1);
|
||||
window.r.bg3.belowEnable = data.bit(2);
|
||||
window.r.bg4.belowEnable = data.bit(3);
|
||||
window.r.obj.belowEnable = data.bit(4);
|
||||
window.io.bg1.belowEnable = data.bit(0);
|
||||
window.io.bg2.belowEnable = data.bit(1);
|
||||
window.io.bg3.belowEnable = data.bit(2);
|
||||
window.io.bg4.belowEnable = data.bit(3);
|
||||
window.io.obj.belowEnable = data.bit(4);
|
||||
return;
|
||||
}
|
||||
|
||||
//CGWSEL
|
||||
case 0x2130: {
|
||||
screen.r.directColor = data.bit (0);
|
||||
screen.r.blendMode = data.bit (1);
|
||||
window.r.col.belowMask = data.bits(4,5);
|
||||
window.r.col.aboveMask = data.bits(6,7);
|
||||
screen.io.directColor = data.bit (0);
|
||||
screen.io.blendMode = data.bit (1);
|
||||
window.io.col.belowMask = data.bits(4,5);
|
||||
window.io.col.aboveMask = data.bits(6,7);
|
||||
return;
|
||||
}
|
||||
|
||||
//CGADDSUB
|
||||
case 0x2131: {
|
||||
screen.r.bg1.colorEnable = data.bit(0);
|
||||
screen.r.bg2.colorEnable = data.bit(1);
|
||||
screen.r.bg3.colorEnable = data.bit(2);
|
||||
screen.r.bg4.colorEnable = data.bit(3);
|
||||
screen.r.obj.colorEnable = data.bit(4);
|
||||
screen.r.back.colorEnable = data.bit(5);
|
||||
screen.r.colorHalve = data.bit(6);
|
||||
screen.r.colorMode = data.bit(7);
|
||||
screen.io.bg1.colorEnable = data.bit(0);
|
||||
screen.io.bg2.colorEnable = data.bit(1);
|
||||
screen.io.bg3.colorEnable = data.bit(2);
|
||||
screen.io.bg4.colorEnable = data.bit(3);
|
||||
screen.io.obj.colorEnable = data.bit(4);
|
||||
screen.io.back.colorEnable = data.bit(5);
|
||||
screen.io.colorHalve = data.bit(6);
|
||||
screen.io.colorMode = data.bit(7);
|
||||
return;
|
||||
}
|
||||
|
||||
//COLDATA
|
||||
case 0x2132: {
|
||||
if(data.bit(5)) screen.r.colorRed = data.bits(0,4);
|
||||
if(data.bit(6)) screen.r.colorGreen = data.bits(0,4);
|
||||
if(data.bit(7)) screen.r.colorBlue = data.bits(0,4);
|
||||
if(data.bit(5)) screen.io.colorRed = data.bits(0,4);
|
||||
if(data.bit(6)) screen.io.colorGreen = data.bits(0,4);
|
||||
if(data.bit(7)) screen.io.colorBlue = data.bits(0,4);
|
||||
return;
|
||||
}
|
||||
|
||||
//SETINI
|
||||
case 0x2133: {
|
||||
r.interlace = data.bit(0);
|
||||
obj.r.interlace = data.bit(1);
|
||||
r.overscan = data.bit(2);
|
||||
r.pseudoHires = data.bit(3);
|
||||
r.extbg = data.bit(6);
|
||||
io.interlace = data.bit(0);
|
||||
obj.io.interlace = data.bit(1);
|
||||
io.overscan = data.bit(2);
|
||||
io.pseudoHires = data.bit(3);
|
||||
io.extbg = data.bit(6);
|
||||
updateVideoMode();
|
||||
return;
|
||||
}
|
||||
|
@ -622,108 +617,108 @@ auto PPU::writeIO(uint24 addr, uint8 data) -> void {
|
|||
|
||||
auto PPU::latchCounters() -> void {
|
||||
cpu.synchronizePPU();
|
||||
r.hcounter = hdot();
|
||||
r.vcounter = vcounter();
|
||||
io.hcounter = hdot();
|
||||
io.vcounter = vcounter();
|
||||
latch.counters = true;
|
||||
}
|
||||
|
||||
auto PPU::updateVideoMode() -> void {
|
||||
switch(r.bgMode) {
|
||||
switch(io.bgMode) {
|
||||
case 0:
|
||||
bg1.r.mode = Background::Mode::BPP2;
|
||||
bg2.r.mode = Background::Mode::BPP2;
|
||||
bg3.r.mode = Background::Mode::BPP2;
|
||||
bg4.r.mode = Background::Mode::BPP2;
|
||||
memory::assign(bg1.r.priority, 8, 11);
|
||||
memory::assign(bg2.r.priority, 7, 10);
|
||||
memory::assign(bg3.r.priority, 2, 5);
|
||||
memory::assign(bg4.r.priority, 1, 4);
|
||||
memory::assign(obj.r.priority, 3, 6, 9, 12);
|
||||
bg1.io.mode = Background::Mode::BPP2;
|
||||
bg2.io.mode = Background::Mode::BPP2;
|
||||
bg3.io.mode = Background::Mode::BPP2;
|
||||
bg4.io.mode = Background::Mode::BPP2;
|
||||
memory::assign(bg1.io.priority, 8, 11);
|
||||
memory::assign(bg2.io.priority, 7, 10);
|
||||
memory::assign(bg3.io.priority, 2, 5);
|
||||
memory::assign(bg4.io.priority, 1, 4);
|
||||
memory::assign(obj.io.priority, 3, 6, 9, 12);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
bg1.r.mode = Background::Mode::BPP4;
|
||||
bg2.r.mode = Background::Mode::BPP4;
|
||||
bg3.r.mode = Background::Mode::BPP2;
|
||||
bg4.r.mode = Background::Mode::Inactive;
|
||||
if(r.bgPriority) {
|
||||
memory::assign(bg1.r.priority, 5, 8);
|
||||
memory::assign(bg2.r.priority, 4, 7);
|
||||
memory::assign(bg3.r.priority, 1, 10);
|
||||
memory::assign(obj.r.priority, 2, 3, 6, 9);
|
||||
bg1.io.mode = Background::Mode::BPP4;
|
||||
bg2.io.mode = Background::Mode::BPP4;
|
||||
bg3.io.mode = Background::Mode::BPP2;
|
||||
bg4.io.mode = Background::Mode::Inactive;
|
||||
if(io.bgPriority) {
|
||||
memory::assign(bg1.io.priority, 5, 8);
|
||||
memory::assign(bg2.io.priority, 4, 7);
|
||||
memory::assign(bg3.io.priority, 1, 10);
|
||||
memory::assign(obj.io.priority, 2, 3, 6, 9);
|
||||
} else {
|
||||
memory::assign(bg1.r.priority, 6, 9);
|
||||
memory::assign(bg2.r.priority, 5, 8);
|
||||
memory::assign(bg3.r.priority, 1, 3);
|
||||
memory::assign(obj.r.priority, 2, 4, 7, 10);
|
||||
memory::assign(bg1.io.priority, 6, 9);
|
||||
memory::assign(bg2.io.priority, 5, 8);
|
||||
memory::assign(bg3.io.priority, 1, 3);
|
||||
memory::assign(obj.io.priority, 2, 4, 7, 10);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
bg1.r.mode = Background::Mode::BPP4;
|
||||
bg2.r.mode = Background::Mode::BPP4;
|
||||
bg3.r.mode = Background::Mode::Inactive;
|
||||
bg4.r.mode = Background::Mode::Inactive;
|
||||
memory::assign(bg1.r.priority, 3, 7);
|
||||
memory::assign(bg2.r.priority, 1, 5);
|
||||
memory::assign(obj.r.priority, 2, 4, 6, 8);
|
||||
bg1.io.mode = Background::Mode::BPP4;
|
||||
bg2.io.mode = Background::Mode::BPP4;
|
||||
bg3.io.mode = Background::Mode::Inactive;
|
||||
bg4.io.mode = Background::Mode::Inactive;
|
||||
memory::assign(bg1.io.priority, 3, 7);
|
||||
memory::assign(bg2.io.priority, 1, 5);
|
||||
memory::assign(obj.io.priority, 2, 4, 6, 8);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
bg1.r.mode = Background::Mode::BPP8;
|
||||
bg2.r.mode = Background::Mode::BPP4;
|
||||
bg3.r.mode = Background::Mode::Inactive;
|
||||
bg4.r.mode = Background::Mode::Inactive;
|
||||
memory::assign(bg1.r.priority, 3, 7);
|
||||
memory::assign(bg2.r.priority, 1, 5);
|
||||
memory::assign(obj.r.priority, 2, 4, 6, 8);
|
||||
bg1.io.mode = Background::Mode::BPP8;
|
||||
bg2.io.mode = Background::Mode::BPP4;
|
||||
bg3.io.mode = Background::Mode::Inactive;
|
||||
bg4.io.mode = Background::Mode::Inactive;
|
||||
memory::assign(bg1.io.priority, 3, 7);
|
||||
memory::assign(bg2.io.priority, 1, 5);
|
||||
memory::assign(obj.io.priority, 2, 4, 6, 8);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
bg1.r.mode = Background::Mode::BPP8;
|
||||
bg2.r.mode = Background::Mode::BPP2;
|
||||
bg3.r.mode = Background::Mode::Inactive;
|
||||
bg4.r.mode = Background::Mode::Inactive;
|
||||
memory::assign(bg1.r.priority, 3, 7);
|
||||
memory::assign(bg2.r.priority, 1, 5);
|
||||
memory::assign(obj.r.priority, 2, 4, 6, 8);
|
||||
bg1.io.mode = Background::Mode::BPP8;
|
||||
bg2.io.mode = Background::Mode::BPP2;
|
||||
bg3.io.mode = Background::Mode::Inactive;
|
||||
bg4.io.mode = Background::Mode::Inactive;
|
||||
memory::assign(bg1.io.priority, 3, 7);
|
||||
memory::assign(bg2.io.priority, 1, 5);
|
||||
memory::assign(obj.io.priority, 2, 4, 6, 8);
|
||||
break;
|
||||
|
||||
case 5:
|
||||
bg1.r.mode = Background::Mode::BPP4;
|
||||
bg2.r.mode = Background::Mode::BPP2;
|
||||
bg3.r.mode = Background::Mode::Inactive;
|
||||
bg4.r.mode = Background::Mode::Inactive;
|
||||
memory::assign(bg1.r.priority, 3, 7);
|
||||
memory::assign(bg2.r.priority, 1, 5);
|
||||
memory::assign(obj.r.priority, 2, 4, 6, 8);
|
||||
bg1.io.mode = Background::Mode::BPP4;
|
||||
bg2.io.mode = Background::Mode::BPP2;
|
||||
bg3.io.mode = Background::Mode::Inactive;
|
||||
bg4.io.mode = Background::Mode::Inactive;
|
||||
memory::assign(bg1.io.priority, 3, 7);
|
||||
memory::assign(bg2.io.priority, 1, 5);
|
||||
memory::assign(obj.io.priority, 2, 4, 6, 8);
|
||||
break;
|
||||
|
||||
case 6:
|
||||
bg1.r.mode = Background::Mode::BPP4;
|
||||
bg2.r.mode = Background::Mode::Inactive;
|
||||
bg3.r.mode = Background::Mode::Inactive;
|
||||
bg4.r.mode = Background::Mode::Inactive;
|
||||
memory::assign(bg1.r.priority, 2, 5);
|
||||
memory::assign(obj.r.priority, 1, 3, 4, 6);
|
||||
bg1.io.mode = Background::Mode::BPP4;
|
||||
bg2.io.mode = Background::Mode::Inactive;
|
||||
bg3.io.mode = Background::Mode::Inactive;
|
||||
bg4.io.mode = Background::Mode::Inactive;
|
||||
memory::assign(bg1.io.priority, 2, 5);
|
||||
memory::assign(obj.io.priority, 1, 3, 4, 6);
|
||||
break;
|
||||
|
||||
case 7:
|
||||
if(!r.extbg) {
|
||||
bg1.r.mode = Background::Mode::Mode7;
|
||||
bg2.r.mode = Background::Mode::Inactive;
|
||||
bg3.r.mode = Background::Mode::Inactive;
|
||||
bg4.r.mode = Background::Mode::Inactive;
|
||||
memory::assign(bg1.r.priority, 2);
|
||||
memory::assign(obj.r.priority, 1, 3, 4, 5);
|
||||
if(!io.extbg) {
|
||||
bg1.io.mode = Background::Mode::Mode7;
|
||||
bg2.io.mode = Background::Mode::Inactive;
|
||||
bg3.io.mode = Background::Mode::Inactive;
|
||||
bg4.io.mode = Background::Mode::Inactive;
|
||||
memory::assign(bg1.io.priority, 2);
|
||||
memory::assign(obj.io.priority, 1, 3, 4, 5);
|
||||
} else {
|
||||
bg1.r.mode = Background::Mode::Mode7;
|
||||
bg2.r.mode = Background::Mode::Mode7;
|
||||
bg3.r.mode = Background::Mode::Inactive;
|
||||
bg4.r.mode = Background::Mode::Inactive;
|
||||
memory::assign(bg1.r.priority, 3);
|
||||
memory::assign(bg2.r.priority, 1, 5);
|
||||
memory::assign(obj.r.priority, 2, 4, 6, 7);
|
||||
bg1.io.mode = Background::Mode::Mode7;
|
||||
bg2.io.mode = Background::Mode::Mode7;
|
||||
bg3.io.mode = Background::Mode::Inactive;
|
||||
bg4.io.mode = Background::Mode::Inactive;
|
||||
memory::assign(bg1.io.priority, 3);
|
||||
memory::assign(bg2.io.priority, 1, 5);
|
||||
memory::assign(obj.io.priority, 2, 4, 6, 7);
|
||||
}
|
||||
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 {
|
||||
ppu.r.oamAddress = ppu.r.oamBaseAddress;
|
||||
ppu.io.oamAddress = ppu.io.oamBaseAddress;
|
||||
setFirstSprite();
|
||||
}
|
||||
|
||||
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 {
|
||||
r.timeOver = false;
|
||||
r.rangeOver = false;
|
||||
io.timeOver = false;
|
||||
io.rangeOver = false;
|
||||
}
|
||||
|
||||
auto PPU::Object::scanline() -> void {
|
||||
|
@ -25,15 +25,15 @@ auto PPU::Object::scanline() -> void {
|
|||
auto oamItem = t.item[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;
|
||||
|
||||
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(128)) {
|
||||
uint7 sprite = r.firstSprite + n;
|
||||
if(!onScanline(list[sprite])) continue;
|
||||
uint7 sprite = io.firstSprite + n;
|
||||
if(!onScanline(oam.object[sprite])) continue;
|
||||
if(t.itemCount++ >= 32) break;
|
||||
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;
|
||||
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((sprite.y + height) >= 256 && t.y < ((sprite.y + height) & 255)) return true;
|
||||
return false;
|
||||
|
@ -72,14 +72,14 @@ auto PPU::Object::run() -> void {
|
|||
color += tile.data >> (shift + 21) & 8;
|
||||
|
||||
if(color) {
|
||||
if(r.aboveEnable) {
|
||||
if(io.aboveEnable) {
|
||||
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.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--) {
|
||||
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;
|
||||
int x = sprite.x;
|
||||
int y = (t.y - sprite.y) & 0xff;
|
||||
if(r.interlace) y <<= 1;
|
||||
if(io.interlace) y <<= 1;
|
||||
|
||||
if(sprite.vflip) {
|
||||
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();
|
||||
}
|
||||
|
||||
x &= 511;
|
||||
y &= 255;
|
||||
|
||||
uint16 tiledataAddress = r.tiledataAddress;
|
||||
uint16 tiledataAddress = io.tiledataAddress;
|
||||
uint16 chrx = (sprite.character >> 0) & 15;
|
||||
uint16 chry = (sprite.character >> 4) & 15;
|
||||
if(sprite.nameSelect) {
|
||||
tiledataAddress += (256 * 16) + (r.nameSelect << 12);
|
||||
if(sprite.nameselect) {
|
||||
tiledataAddress += (256 * 16) + (io.nameselect << 12);
|
||||
}
|
||||
chry += (y >> 3);
|
||||
chry &= 15;
|
||||
|
@ -142,31 +142,30 @@ auto PPU::Object::tilefetch() -> void {
|
|||
uint16 addr = (pos & 0xfff0) + (y & 7);
|
||||
|
||||
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];
|
||||
ppu.addClocks(2);
|
||||
ppu.step(2);
|
||||
}
|
||||
}
|
||||
|
||||
if(t.tileCount < 34) ppu.addClocks((34 - t.tileCount) * 4);
|
||||
r.timeOver |= (t.tileCount > 34);
|
||||
r.rangeOver |= (t.itemCount > 32);
|
||||
if(t.tileCount < 34) ppu.step((34 - t.tileCount) * 4);
|
||||
io.timeOver |= (t.tileCount > 34);
|
||||
io.rangeOver |= (t.itemCount > 32);
|
||||
}
|
||||
|
||||
auto PPU::Object::reset() -> void {
|
||||
for(auto n : range(128)) {
|
||||
list[n].x = 0;
|
||||
list[n].y = 0;
|
||||
list[n].character = 0;
|
||||
list[n].nameSelect = 0;
|
||||
list[n].vflip = 0;
|
||||
list[n].hflip = 0;
|
||||
list[n].priority = 0;
|
||||
list[n].palette = 0;
|
||||
list[n].size = 0;
|
||||
for(auto& object : oam.object) {
|
||||
object.x = 0;
|
||||
object.y = 0;
|
||||
object.character = 0;
|
||||
object.nameselect = 0;
|
||||
object.vflip = 0;
|
||||
object.hflip = 0;
|
||||
object.priority = 0;
|
||||
object.palette = 0;
|
||||
object.size = 0;
|
||||
}
|
||||
synchronize();
|
||||
|
||||
t.x = 0;
|
||||
t.y = 0;
|
||||
|
@ -190,19 +189,19 @@ auto PPU::Object::reset() -> void {
|
|||
}
|
||||
}
|
||||
|
||||
r.aboveEnable = random(false);
|
||||
r.belowEnable = random(false);
|
||||
r.interlace = random(false);
|
||||
io.aboveEnable = random(false);
|
||||
io.belowEnable = random(false);
|
||||
io.interlace = random(false);
|
||||
|
||||
r.baseSize = random(0);
|
||||
r.nameSelect = random(0);
|
||||
r.tiledataAddress = (random(0x0000) & 3) << 13;
|
||||
r.firstSprite = 0;
|
||||
io.baseSize = random(0);
|
||||
io.nameselect = random(0);
|
||||
io.tiledataAddress = (random(0x0000) & 7) << 13;
|
||||
io.firstSprite = 0;
|
||||
|
||||
for(auto& p : r.priority) p = 0;
|
||||
for(auto& p : io.priority) p = 0;
|
||||
|
||||
r.timeOver = false;
|
||||
r.rangeOver = false;
|
||||
io.timeOver = false;
|
||||
io.rangeOver = false;
|
||||
|
||||
output.above.palette = 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 {
|
||||
alwaysinline auto addressReset() -> void;
|
||||
alwaysinline auto setFirstSprite() -> void;
|
||||
|
@ -7,22 +27,19 @@ struct Object {
|
|||
auto tilefetch() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
struct Sprite;
|
||||
auto onScanline(Sprite&) -> bool;
|
||||
|
||||
//list.cpp
|
||||
auto update(uint10 addr, uint8 data) -> void;
|
||||
auto synchronize() -> void;
|
||||
auto onScanline(PPU::OAM::Object&) -> bool;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
struct Registers {
|
||||
OAM oam;
|
||||
|
||||
struct IO {
|
||||
bool aboveEnable;
|
||||
bool belowEnable;
|
||||
bool interlace;
|
||||
|
||||
uint3 baseSize;
|
||||
uint2 nameSelect;
|
||||
uint2 nameselect;
|
||||
uint16 tiledataAddress;
|
||||
uint7 firstSprite;
|
||||
|
||||
|
@ -30,7 +47,7 @@ struct Object {
|
|||
|
||||
bool timeOver;
|
||||
bool rangeOver;
|
||||
} r;
|
||||
} io;
|
||||
|
||||
struct Item {
|
||||
bool valid;
|
||||
|
@ -65,20 +82,5 @@ struct Object {
|
|||
} above, below;
|
||||
} 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;
|
||||
};
|
||||
|
|
|
@ -29,7 +29,12 @@ PPU::~PPU() {
|
|||
}
|
||||
|
||||
auto PPU::step(uint clocks) -> void {
|
||||
clock += clocks;
|
||||
clocks >>= 1;
|
||||
while(clocks--) {
|
||||
tick(2);
|
||||
clock += 2;
|
||||
synchronizeCPU();
|
||||
}
|
||||
}
|
||||
|
||||
auto PPU::synchronizeCPU() -> void {
|
||||
|
@ -42,7 +47,7 @@ auto PPU::Enter() -> void {
|
|||
|
||||
auto PPU::main() -> void {
|
||||
scanline();
|
||||
addClocks(28);
|
||||
step(28);
|
||||
bg1.begin();
|
||||
bg2.begin();
|
||||
bg3.begin();
|
||||
|
@ -54,7 +59,7 @@ auto PPU::main() -> void {
|
|||
bg2.run(1);
|
||||
bg3.run(1);
|
||||
bg4.run(1);
|
||||
addClocks(2);
|
||||
step(2);
|
||||
|
||||
bg1.run(0);
|
||||
bg2.run(0);
|
||||
|
@ -65,25 +70,16 @@ auto PPU::main() -> void {
|
|||
window.run();
|
||||
screen.run();
|
||||
}
|
||||
addClocks(2);
|
||||
step(2);
|
||||
}
|
||||
|
||||
addClocks(14);
|
||||
step(14);
|
||||
obj.tilefetch();
|
||||
} else {
|
||||
addClocks(1052 + 14 + 136);
|
||||
step(1052 + 14 + 136);
|
||||
}
|
||||
|
||||
addClocks(lineclocks() - 28 - 1052 - 14 - 136);
|
||||
}
|
||||
|
||||
auto PPU::addClocks(uint clocks) -> void {
|
||||
clocks >>= 1;
|
||||
while(clocks--) {
|
||||
tick(2);
|
||||
step(2);
|
||||
synchronizeCPU();
|
||||
}
|
||||
step(lineclocks() - 28 - 1052 - 14 - 136);
|
||||
}
|
||||
|
||||
auto PPU::load(Markup::Node node) -> bool {
|
||||
|
@ -96,8 +92,6 @@ auto PPU::load(Markup::Node node) -> bool {
|
|||
|
||||
auto PPU::power() -> void {
|
||||
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 {
|
||||
|
@ -125,72 +119,72 @@ auto PPU::reset() -> void {
|
|||
latch.cgramAddress = 0x00;
|
||||
|
||||
//$2100 INIDISP
|
||||
r.displayDisable = true;
|
||||
r.displayBrightness = 0;
|
||||
io.displayDisable = true;
|
||||
io.displayBrightness = 0;
|
||||
|
||||
//$2102 OAMADDL
|
||||
//$2103 OAMADDH
|
||||
r.oamBaseAddress = random(0x0000);
|
||||
r.oamAddress = random(0x0000);
|
||||
r.oamPriority = random(false);
|
||||
io.oamBaseAddress = random(0x0000);
|
||||
io.oamAddress = random(0x0000);
|
||||
io.oamPriority = random(false);
|
||||
|
||||
//$2105 BGMODE
|
||||
r.bgPriority = false;
|
||||
r.bgMode = 0;
|
||||
io.bgPriority = false;
|
||||
io.bgMode = 0;
|
||||
|
||||
//$210d BG1HOFS
|
||||
r.hoffsetMode7 = random(0x0000);
|
||||
io.hoffsetMode7 = random(0x0000);
|
||||
|
||||
//$210e BG1VOFS
|
||||
r.voffsetMode7 = random(0x0000);
|
||||
io.voffsetMode7 = random(0x0000);
|
||||
|
||||
//$2115 VMAIN
|
||||
r.vramIncrementMode = random(1);
|
||||
r.vramMapping = random(0);
|
||||
r.vramIncrementSize = 1;
|
||||
io.vramIncrementMode = random(1);
|
||||
io.vramMapping = random(0);
|
||||
io.vramIncrementSize = 1;
|
||||
|
||||
//$2116 VMADDL
|
||||
//$2117 VMADDH
|
||||
r.vramAddress = random(0x0000);
|
||||
io.vramAddress = random(0x0000);
|
||||
|
||||
//$211a M7SEL
|
||||
r.repeatMode7 = random(0);
|
||||
r.vflipMode7 = random(false);
|
||||
r.hflipMode7 = random(false);
|
||||
io.repeatMode7 = random(0);
|
||||
io.vflipMode7 = random(false);
|
||||
io.hflipMode7 = random(false);
|
||||
|
||||
//$211b M7A
|
||||
r.m7a = random(0x0000);
|
||||
io.m7a = random(0x0000);
|
||||
|
||||
//$211c M7B
|
||||
r.m7b = random(0x0000);
|
||||
io.m7b = random(0x0000);
|
||||
|
||||
//$211d M7C
|
||||
r.m7c = random(0x0000);
|
||||
io.m7c = random(0x0000);
|
||||
|
||||
//$211e M7D
|
||||
r.m7d = random(0x0000);
|
||||
io.m7d = random(0x0000);
|
||||
|
||||
//$211f M7X
|
||||
r.m7x = random(0x0000);
|
||||
io.m7x = random(0x0000);
|
||||
|
||||
//$2120 M7Y
|
||||
r.m7y = random(0x0000);
|
||||
io.m7y = random(0x0000);
|
||||
|
||||
//$2121 CGADD
|
||||
r.cgramAddress = random(0x00);
|
||||
r.cgramAddressLatch = random(0);
|
||||
io.cgramAddress = random(0x00);
|
||||
io.cgramAddressLatch = random(0);
|
||||
|
||||
//$2133 SETINI
|
||||
r.extbg = random(false);
|
||||
r.pseudoHires = random(false);
|
||||
r.overscan = false;
|
||||
r.interlace = false;
|
||||
io.extbg = random(false);
|
||||
io.pseudoHires = random(false);
|
||||
io.overscan = false;
|
||||
io.interlace = false;
|
||||
|
||||
//$213c OPHCT
|
||||
r.hcounter = 0;
|
||||
io.hcounter = 0;
|
||||
|
||||
//$213d OPVCT
|
||||
r.vcounter = 0;
|
||||
io.vcounter = 0;
|
||||
|
||||
bg1.reset();
|
||||
bg2.reset();
|
||||
|
@ -227,8 +221,8 @@ auto PPU::scanline() -> void {
|
|||
|
||||
auto PPU::frame() -> void {
|
||||
obj.frame();
|
||||
display.interlace = r.interlace;
|
||||
display.overscan = r.overscan;
|
||||
display.interlace = io.interlace;
|
||||
display.overscan = io.overscan;
|
||||
}
|
||||
|
||||
auto PPU::refresh() -> void {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
struct PPU : Thread, PPUcounter {
|
||||
alwaysinline auto interlace() const -> bool { return display.interlace; }
|
||||
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();
|
||||
|
@ -33,16 +33,6 @@ privileged:
|
|||
uint mask = 0x7fff;
|
||||
} 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;
|
||||
|
||||
struct {
|
||||
|
@ -50,8 +40,6 @@ privileged:
|
|||
bool overscan;
|
||||
} display;
|
||||
|
||||
alwaysinline auto addClocks(uint) -> void;
|
||||
|
||||
auto scanline() -> void;
|
||||
auto frame() -> void;
|
||||
auto refresh() -> void;
|
||||
|
@ -75,7 +63,7 @@ privileged:
|
|||
uint8 cgramAddress;
|
||||
} latch;
|
||||
|
||||
struct Registers {
|
||||
struct IO {
|
||||
//$2100 INIDISP
|
||||
bool displayDisable;
|
||||
uint4 displayBrightness;
|
||||
|
@ -143,7 +131,7 @@ privileged:
|
|||
|
||||
//$213d OPVCT
|
||||
uint16 vcounter;
|
||||
} r;
|
||||
} io;
|
||||
|
||||
#include "background/background.hpp"
|
||||
#include "object/object.hpp"
|
||||
|
|
|
@ -8,32 +8,32 @@ auto PPU::Screen::scanline() -> void {
|
|||
math.above.color = paletteColor(0);
|
||||
math.below.color = math.above.color;
|
||||
|
||||
math.above.colorEnable = !(ppu.window.r.col.aboveMask & 1);
|
||||
math.below.colorEnable = !(ppu.window.r.col.belowMask & 1) && r.back.colorEnable;
|
||||
math.above.colorEnable = !(ppu.window.io.col.aboveMask & 1);
|
||||
math.below.colorEnable = !(ppu.window.io.col.belowMask & 1) && io.back.colorEnable;
|
||||
|
||||
math.transparent = true;
|
||||
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 {
|
||||
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 aboveColor = above();
|
||||
|
||||
*lineA++ = *lineB++ = ppu.r.displayBrightness << 15 | (hires ? belowColor : aboveColor);
|
||||
*lineA++ = *lineB++ = ppu.r.displayBrightness << 15 | (aboveColor);
|
||||
*lineA++ = *lineB++ = ppu.io.displayBrightness << 15 | (hires ? belowColor : aboveColor);
|
||||
*lineA++ = *lineB++ = ppu.io.displayBrightness << 15 | (aboveColor);
|
||||
}
|
||||
|
||||
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;
|
||||
if(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);
|
||||
} else {
|
||||
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 {
|
||||
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;
|
||||
if(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);
|
||||
} else {
|
||||
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) {
|
||||
priority = ppu.bg2.output.above.priority;
|
||||
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) {
|
||||
priority = ppu.bg3.output.above.priority;
|
||||
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) {
|
||||
priority = ppu.bg4.output.above.priority;
|
||||
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) {
|
||||
priority = ppu.obj.output.above.priority;
|
||||
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) {
|
||||
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;
|
||||
math.above.colorEnable = ppu.window.output.above.colorEnable;
|
||||
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.colorHalve = false;
|
||||
} else {
|
||||
math.blendMode = r.blendMode;
|
||||
math.colorHalve = r.colorHalve && math.above.colorEnable;
|
||||
math.blendMode = io.blendMode;
|
||||
math.colorHalve = io.colorHalve && math.above.colorEnable;
|
||||
}
|
||||
|
||||
return blend(
|
||||
|
@ -123,7 +123,7 @@ auto PPU::Screen::above() -> uint16 {
|
|||
}
|
||||
|
||||
auto PPU::Screen::blend(uint x, uint y) const -> uint15 {
|
||||
if(!r.colorMode) {
|
||||
if(!io.colorMode) {
|
||||
if(!math.colorHalve) {
|
||||
uint sum = x + y;
|
||||
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 {
|
||||
ppu.latch.cgramAddress = palette;
|
||||
return ppu.cgram[palette];
|
||||
return cgram[palette];
|
||||
}
|
||||
|
||||
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 {
|
||||
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 {
|
||||
r.blendMode = random(false);
|
||||
r.directColor = random(false);
|
||||
r.colorMode = random(false);
|
||||
r.colorHalve = random(false);
|
||||
r.bg1.colorEnable = random(false);
|
||||
r.bg2.colorEnable = random(false);
|
||||
r.bg3.colorEnable = random(false);
|
||||
r.bg4.colorEnable = random(false);
|
||||
r.obj.colorEnable = random(false);
|
||||
r.back.colorEnable = random(false);
|
||||
r.colorBlue = random(0);
|
||||
r.colorGreen = random(0);
|
||||
r.colorRed = random(0);
|
||||
for(auto& n : cgram) n = random(0x0000);
|
||||
|
||||
io.blendMode = random(false);
|
||||
io.directColor = random(false);
|
||||
io.colorMode = random(false);
|
||||
io.colorHalve = random(false);
|
||||
io.bg1.colorEnable = random(false);
|
||||
io.bg2.colorEnable = random(false);
|
||||
io.bg3.colorEnable = random(false);
|
||||
io.bg4.colorEnable = random(false);
|
||||
io.obj.colorEnable = random(false);
|
||||
io.back.colorEnable = random(false);
|
||||
io.colorBlue = random(0);
|
||||
io.colorGreen = random(0);
|
||||
io.colorRed = random(0);
|
||||
}
|
||||
|
|
|
@ -16,7 +16,9 @@ struct Screen {
|
|||
uint32* lineA;
|
||||
uint32* lineB;
|
||||
|
||||
struct Registers {
|
||||
uint15 cgram[256];
|
||||
|
||||
struct IO {
|
||||
bool blendMode;
|
||||
bool directColor;
|
||||
|
||||
|
@ -29,7 +31,7 @@ struct Screen {
|
|||
uint5 colorBlue;
|
||||
uint5 colorGreen;
|
||||
uint5 colorRed;
|
||||
} r;
|
||||
} io;
|
||||
|
||||
struct Math {
|
||||
struct Screen {
|
||||
|
|
|
@ -16,8 +16,6 @@ auto PPU::serialize(serializer& s) -> void {
|
|||
|
||||
s.integer(vram.mask);
|
||||
s.array(vram.data, vram.mask + 1);
|
||||
s.array(oam.data);
|
||||
s.array(cgram.data);
|
||||
|
||||
s.integer(ppu1.version);
|
||||
s.integer(ppu1.mdr);
|
||||
|
@ -40,46 +38,46 @@ auto PPU::serialize(serializer& s) -> void {
|
|||
s.integer(latch.oamAddress);
|
||||
s.integer(latch.cgramAddress);
|
||||
|
||||
s.integer(r.displayDisable);
|
||||
s.integer(r.displayBrightness);
|
||||
s.integer(io.displayDisable);
|
||||
s.integer(io.displayBrightness);
|
||||
|
||||
s.integer(r.oamBaseAddress);
|
||||
s.integer(r.oamAddress);
|
||||
s.integer(r.oamPriority);
|
||||
s.integer(io.oamBaseAddress);
|
||||
s.integer(io.oamAddress);
|
||||
s.integer(io.oamPriority);
|
||||
|
||||
s.integer(r.bgPriority);
|
||||
s.integer(r.bgMode);
|
||||
s.integer(io.bgPriority);
|
||||
s.integer(io.bgMode);
|
||||
|
||||
s.integer(r.hoffsetMode7);
|
||||
s.integer(r.voffsetMode7);
|
||||
s.integer(io.hoffsetMode7);
|
||||
s.integer(io.voffsetMode7);
|
||||
|
||||
s.integer(r.vramIncrementMode);
|
||||
s.integer(r.vramMapping);
|
||||
s.integer(r.vramIncrementSize);
|
||||
s.integer(io.vramIncrementMode);
|
||||
s.integer(io.vramMapping);
|
||||
s.integer(io.vramIncrementSize);
|
||||
|
||||
s.integer(r.vramAddress);
|
||||
s.integer(io.vramAddress);
|
||||
|
||||
s.integer(r.repeatMode7);
|
||||
s.integer(r.vflipMode7);
|
||||
s.integer(r.hflipMode7);
|
||||
s.integer(io.repeatMode7);
|
||||
s.integer(io.vflipMode7);
|
||||
s.integer(io.hflipMode7);
|
||||
|
||||
s.integer(r.m7a);
|
||||
s.integer(r.m7b);
|
||||
s.integer(r.m7c);
|
||||
s.integer(r.m7d);
|
||||
s.integer(r.m7x);
|
||||
s.integer(r.m7y);
|
||||
s.integer(io.m7a);
|
||||
s.integer(io.m7b);
|
||||
s.integer(io.m7c);
|
||||
s.integer(io.m7d);
|
||||
s.integer(io.m7x);
|
||||
s.integer(io.m7y);
|
||||
|
||||
s.integer(r.cgramAddress);
|
||||
s.integer(r.cgramAddressLatch);
|
||||
s.integer(io.cgramAddress);
|
||||
s.integer(io.cgramAddressLatch);
|
||||
|
||||
s.integer(r.extbg);
|
||||
s.integer(r.pseudoHires);
|
||||
s.integer(r.overscan);
|
||||
s.integer(r.interlace);
|
||||
s.integer(io.extbg);
|
||||
s.integer(io.pseudoHires);
|
||||
s.integer(io.overscan);
|
||||
s.integer(io.interlace);
|
||||
|
||||
s.integer(r.hcounter);
|
||||
s.integer(r.vcounter);
|
||||
s.integer(io.hcounter);
|
||||
s.integer(io.vcounter);
|
||||
|
||||
bg1.serialize(s);
|
||||
bg2.serialize(s);
|
||||
|
@ -91,20 +89,20 @@ auto PPU::serialize(serializer& s) -> void {
|
|||
}
|
||||
|
||||
auto PPU::Background::serialize(serializer& s) -> void {
|
||||
s.integer(r.tiledataAddress);
|
||||
s.integer(r.screenAddress);
|
||||
s.integer(r.screenSize);
|
||||
s.integer(r.mosaic);
|
||||
s.integer(r.tileSize);
|
||||
s.integer(io.tiledataAddress);
|
||||
s.integer(io.screenAddress);
|
||||
s.integer(io.screenSize);
|
||||
s.integer(io.mosaic);
|
||||
s.integer(io.tileSize);
|
||||
|
||||
s.integer(r.mode);
|
||||
s.array(r.priority);
|
||||
s.integer(io.mode);
|
||||
s.array(io.priority);
|
||||
|
||||
s.integer(r.aboveEnable);
|
||||
s.integer(r.belowEnable);
|
||||
s.integer(io.aboveEnable);
|
||||
s.integer(io.belowEnable);
|
||||
|
||||
s.integer(r.hoffset);
|
||||
s.integer(r.voffset);
|
||||
s.integer(io.hoffset);
|
||||
s.integer(io.voffset);
|
||||
|
||||
s.integer(latch.hoffset);
|
||||
s.integer(latch.voffset);
|
||||
|
@ -138,19 +136,31 @@ auto PPU::Background::serialize(serializer& s) -> void {
|
|||
}
|
||||
|
||||
auto PPU::Object::serialize(serializer& s) -> void {
|
||||
s.integer(r.aboveEnable);
|
||||
s.integer(r.belowEnable);
|
||||
s.integer(r.interlace);
|
||||
for(auto& object : oam.object) {
|
||||
s.integer(object.x);
|
||||
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(r.nameSelect);
|
||||
s.integer(r.tiledataAddress);
|
||||
s.integer(r.firstSprite);
|
||||
s.integer(io.aboveEnable);
|
||||
s.integer(io.belowEnable);
|
||||
s.integer(io.interlace);
|
||||
|
||||
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.integer(r.rangeOver);
|
||||
s.array(io.priority);
|
||||
|
||||
s.integer(io.timeOver);
|
||||
s.integer(io.rangeOver);
|
||||
|
||||
s.integer(t.x);
|
||||
s.integer(t.y);
|
||||
|
@ -179,73 +189,61 @@ auto PPU::Object::serialize(serializer& s) -> void {
|
|||
|
||||
s.integer(output.below.priority);
|
||||
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 {
|
||||
s.integer(r.bg1.oneEnable);
|
||||
s.integer(r.bg1.oneInvert);
|
||||
s.integer(r.bg1.twoEnable);
|
||||
s.integer(r.bg1.twoInvert);
|
||||
s.integer(r.bg1.mask);
|
||||
s.integer(r.bg1.aboveEnable);
|
||||
s.integer(r.bg1.belowEnable);
|
||||
s.integer(io.bg1.oneEnable);
|
||||
s.integer(io.bg1.oneInvert);
|
||||
s.integer(io.bg1.twoEnable);
|
||||
s.integer(io.bg1.twoInvert);
|
||||
s.integer(io.bg1.mask);
|
||||
s.integer(io.bg1.aboveEnable);
|
||||
s.integer(io.bg1.belowEnable);
|
||||
|
||||
s.integer(r.bg2.oneEnable);
|
||||
s.integer(r.bg2.oneInvert);
|
||||
s.integer(r.bg2.twoEnable);
|
||||
s.integer(r.bg2.twoInvert);
|
||||
s.integer(r.bg2.mask);
|
||||
s.integer(r.bg2.aboveEnable);
|
||||
s.integer(r.bg2.belowEnable);
|
||||
s.integer(io.bg2.oneEnable);
|
||||
s.integer(io.bg2.oneInvert);
|
||||
s.integer(io.bg2.twoEnable);
|
||||
s.integer(io.bg2.twoInvert);
|
||||
s.integer(io.bg2.mask);
|
||||
s.integer(io.bg2.aboveEnable);
|
||||
s.integer(io.bg2.belowEnable);
|
||||
|
||||
s.integer(r.bg3.oneEnable);
|
||||
s.integer(r.bg3.oneInvert);
|
||||
s.integer(r.bg3.twoEnable);
|
||||
s.integer(r.bg3.twoInvert);
|
||||
s.integer(r.bg3.mask);
|
||||
s.integer(r.bg3.aboveEnable);
|
||||
s.integer(r.bg3.belowEnable);
|
||||
s.integer(io.bg3.oneEnable);
|
||||
s.integer(io.bg3.oneInvert);
|
||||
s.integer(io.bg3.twoEnable);
|
||||
s.integer(io.bg3.twoInvert);
|
||||
s.integer(io.bg3.mask);
|
||||
s.integer(io.bg3.aboveEnable);
|
||||
s.integer(io.bg3.belowEnable);
|
||||
|
||||
s.integer(r.bg4.oneEnable);
|
||||
s.integer(r.bg4.oneInvert);
|
||||
s.integer(r.bg4.twoEnable);
|
||||
s.integer(r.bg4.twoInvert);
|
||||
s.integer(r.bg4.mask);
|
||||
s.integer(r.bg4.aboveEnable);
|
||||
s.integer(r.bg4.belowEnable);
|
||||
s.integer(io.bg4.oneEnable);
|
||||
s.integer(io.bg4.oneInvert);
|
||||
s.integer(io.bg4.twoEnable);
|
||||
s.integer(io.bg4.twoInvert);
|
||||
s.integer(io.bg4.mask);
|
||||
s.integer(io.bg4.aboveEnable);
|
||||
s.integer(io.bg4.belowEnable);
|
||||
|
||||
s.integer(r.obj.oneEnable);
|
||||
s.integer(r.obj.oneInvert);
|
||||
s.integer(r.obj.twoEnable);
|
||||
s.integer(r.obj.twoInvert);
|
||||
s.integer(r.obj.mask);
|
||||
s.integer(r.obj.aboveEnable);
|
||||
s.integer(r.obj.belowEnable);
|
||||
s.integer(io.obj.oneEnable);
|
||||
s.integer(io.obj.oneInvert);
|
||||
s.integer(io.obj.twoEnable);
|
||||
s.integer(io.obj.twoInvert);
|
||||
s.integer(io.obj.mask);
|
||||
s.integer(io.obj.aboveEnable);
|
||||
s.integer(io.obj.belowEnable);
|
||||
|
||||
s.integer(r.col.oneEnable);
|
||||
s.integer(r.col.oneInvert);
|
||||
s.integer(r.col.twoEnable);
|
||||
s.integer(r.col.twoInvert);
|
||||
s.integer(r.col.mask);
|
||||
s.integer(r.col.aboveMask);
|
||||
s.integer(r.col.belowMask);
|
||||
s.integer(io.col.oneEnable);
|
||||
s.integer(io.col.oneInvert);
|
||||
s.integer(io.col.twoEnable);
|
||||
s.integer(io.col.twoInvert);
|
||||
s.integer(io.col.mask);
|
||||
s.integer(io.col.aboveMask);
|
||||
s.integer(io.col.belowMask);
|
||||
|
||||
s.integer(r.oneLeft);
|
||||
s.integer(r.oneRight);
|
||||
s.integer(r.twoLeft);
|
||||
s.integer(r.twoRight);
|
||||
s.integer(io.oneLeft);
|
||||
s.integer(io.oneRight);
|
||||
s.integer(io.twoLeft);
|
||||
s.integer(io.twoRight);
|
||||
|
||||
s.integer(output.above.colorEnable);
|
||||
s.integer(output.below.colorEnable);
|
||||
|
@ -254,21 +252,23 @@ auto PPU::Window::serialize(serializer& s) -> void {
|
|||
}
|
||||
|
||||
auto PPU::Screen::serialize(serializer& s) -> void {
|
||||
s.integer(r.blendMode);
|
||||
s.integer(r.directColor);
|
||||
s.array(cgram);
|
||||
|
||||
s.integer(r.colorMode);
|
||||
s.integer(r.colorHalve);
|
||||
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(io.blendMode);
|
||||
s.integer(io.directColor);
|
||||
|
||||
s.integer(r.colorBlue);
|
||||
s.integer(r.colorGreen);
|
||||
s.integer(r.colorRed);
|
||||
s.integer(io.colorMode);
|
||||
s.integer(io.colorHalve);
|
||||
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.colorEnable);
|
||||
|
|
|
@ -3,39 +3,39 @@ auto PPU::Window::scanline() -> void {
|
|||
}
|
||||
|
||||
auto PPU::Window::run() -> void {
|
||||
bool one = (x >= r.oneLeft && x <= r.oneRight);
|
||||
bool two = (x >= r.twoLeft && x <= r.twoRight);
|
||||
bool one = (x >= io.oneLeft && x <= io.oneRight);
|
||||
bool two = (x >= io.twoLeft && x <= io.twoRight);
|
||||
x++;
|
||||
|
||||
if(test(r.bg1.oneEnable, one ^ r.bg1.oneInvert, r.bg1.twoEnable, two ^ r.bg1.twoInvert, r.bg1.mask)) {
|
||||
if(r.bg1.aboveEnable) ppu.bg1.output.above.priority = 0;
|
||||
if(r.bg1.belowEnable) ppu.bg1.output.below.priority = 0;
|
||||
if(test(io.bg1.oneEnable, one ^ io.bg1.oneInvert, io.bg1.twoEnable, two ^ io.bg1.twoInvert, io.bg1.mask)) {
|
||||
if(io.bg1.aboveEnable) ppu.bg1.output.above.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(r.bg2.aboveEnable) ppu.bg2.output.above.priority = 0;
|
||||
if(r.bg2.belowEnable) ppu.bg2.output.below.priority = 0;
|
||||
if(test(io.bg2.oneEnable, one ^ io.bg2.oneInvert, io.bg2.twoEnable, two ^ io.bg2.twoInvert, io.bg2.mask)) {
|
||||
if(io.bg2.aboveEnable) ppu.bg2.output.above.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(r.bg3.aboveEnable) ppu.bg3.output.above.priority = 0;
|
||||
if(r.bg3.belowEnable) ppu.bg3.output.below.priority = 0;
|
||||
if(test(io.bg3.oneEnable, one ^ io.bg3.oneInvert, io.bg3.twoEnable, two ^ io.bg3.twoInvert, io.bg3.mask)) {
|
||||
if(io.bg3.aboveEnable) ppu.bg3.output.above.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(r.bg4.aboveEnable) ppu.bg4.output.above.priority = 0;
|
||||
if(r.bg4.belowEnable) ppu.bg4.output.below.priority = 0;
|
||||
if(test(io.bg4.oneEnable, one ^ io.bg4.oneInvert, io.bg4.twoEnable, two ^ io.bg4.twoInvert, io.bg4.mask)) {
|
||||
if(io.bg4.aboveEnable) ppu.bg4.output.above.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(r.obj.aboveEnable) ppu.obj.output.above.priority = 0;
|
||||
if(r.obj.belowEnable) ppu.obj.output.below.priority = 0;
|
||||
if(test(io.obj.oneEnable, one ^ io.obj.oneInvert, io.obj.twoEnable, two ^ io.obj.twoInvert, io.obj.mask)) {
|
||||
if(io.obj.aboveEnable) ppu.obj.output.above.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};
|
||||
output.above.colorEnable = array[r.col.aboveMask];
|
||||
output.below.colorEnable = array[r.col.belowMask];
|
||||
output.above.colorEnable = array[io.col.aboveMask];
|
||||
output.below.colorEnable = array[io.col.belowMask];
|
||||
}
|
||||
|
||||
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 {
|
||||
r.bg1.oneEnable = random(false);
|
||||
r.bg1.oneInvert = random(false);
|
||||
r.bg1.twoEnable = random(false);
|
||||
r.bg1.twoInvert = random(false);
|
||||
r.bg1.mask = random(0);
|
||||
r.bg1.aboveEnable = random(false);
|
||||
r.bg1.belowEnable = random(false);
|
||||
io.bg1.oneEnable = random(false);
|
||||
io.bg1.oneInvert = random(false);
|
||||
io.bg1.twoEnable = random(false);
|
||||
io.bg1.twoInvert = random(false);
|
||||
io.bg1.mask = random(0);
|
||||
io.bg1.aboveEnable = random(false);
|
||||
io.bg1.belowEnable = random(false);
|
||||
|
||||
r.bg2.oneEnable = random(false);
|
||||
r.bg2.oneInvert = random(false);
|
||||
r.bg2.twoEnable = random(false);
|
||||
r.bg2.twoInvert = random(false);
|
||||
r.bg2.mask = random(0);
|
||||
r.bg2.aboveEnable = random(false);
|
||||
r.bg2.belowEnable = random(false);
|
||||
io.bg2.oneEnable = random(false);
|
||||
io.bg2.oneInvert = random(false);
|
||||
io.bg2.twoEnable = random(false);
|
||||
io.bg2.twoInvert = random(false);
|
||||
io.bg2.mask = random(0);
|
||||
io.bg2.aboveEnable = random(false);
|
||||
io.bg2.belowEnable = random(false);
|
||||
|
||||
r.bg3.oneEnable = random(false);
|
||||
r.bg3.oneInvert = random(false);
|
||||
r.bg3.twoEnable = random(false);
|
||||
r.bg3.twoInvert = random(false);
|
||||
r.bg3.mask = random(0);
|
||||
r.bg3.aboveEnable = random(false);
|
||||
r.bg3.belowEnable = random(false);
|
||||
io.bg3.oneEnable = random(false);
|
||||
io.bg3.oneInvert = random(false);
|
||||
io.bg3.twoEnable = random(false);
|
||||
io.bg3.twoInvert = random(false);
|
||||
io.bg3.mask = random(0);
|
||||
io.bg3.aboveEnable = random(false);
|
||||
io.bg3.belowEnable = random(false);
|
||||
|
||||
r.bg4.oneEnable = random(false);
|
||||
r.bg4.oneInvert = random(false);
|
||||
r.bg4.twoEnable = random(false);
|
||||
r.bg4.twoInvert = random(false);
|
||||
r.bg4.mask = random(0);
|
||||
r.bg4.aboveEnable = random(false);
|
||||
r.bg4.belowEnable = random(false);
|
||||
io.bg4.oneEnable = random(false);
|
||||
io.bg4.oneInvert = random(false);
|
||||
io.bg4.twoEnable = random(false);
|
||||
io.bg4.twoInvert = random(false);
|
||||
io.bg4.mask = random(0);
|
||||
io.bg4.aboveEnable = random(false);
|
||||
io.bg4.belowEnable = random(false);
|
||||
|
||||
r.obj.oneEnable = random(false);
|
||||
r.obj.oneInvert = random(false);
|
||||
r.obj.twoEnable = random(false);
|
||||
r.obj.twoInvert = random(false);
|
||||
r.obj.mask = random(0);
|
||||
r.obj.aboveEnable = random(false);
|
||||
r.obj.belowEnable = random(false);
|
||||
io.obj.oneEnable = random(false);
|
||||
io.obj.oneInvert = random(false);
|
||||
io.obj.twoEnable = random(false);
|
||||
io.obj.twoInvert = random(false);
|
||||
io.obj.mask = random(0);
|
||||
io.obj.aboveEnable = random(false);
|
||||
io.obj.belowEnable = random(false);
|
||||
|
||||
r.col.oneEnable = random(false);
|
||||
r.col.oneInvert = random(false);
|
||||
r.col.twoEnable = random(false);
|
||||
r.col.twoInvert = random(false);
|
||||
r.col.mask = random(0);
|
||||
r.col.aboveMask = random(0);
|
||||
r.col.belowMask = random(0);
|
||||
io.col.oneEnable = random(false);
|
||||
io.col.oneInvert = random(false);
|
||||
io.col.twoEnable = random(false);
|
||||
io.col.twoInvert = random(false);
|
||||
io.col.mask = random(0);
|
||||
io.col.aboveMask = random(0);
|
||||
io.col.belowMask = random(0);
|
||||
|
||||
r.oneLeft = random(0x00);
|
||||
r.oneRight = random(0x00);
|
||||
r.twoLeft = random(0x00);
|
||||
r.twoRight = random(0x00);
|
||||
io.oneLeft = random(0x00);
|
||||
io.oneRight = random(0x00);
|
||||
io.twoLeft = random(0x00);
|
||||
io.twoRight = random(0x00);
|
||||
|
||||
output.above.colorEnable = 0;
|
||||
output.below.colorEnable = 0;
|
||||
|
|
|
@ -6,7 +6,7 @@ struct Window {
|
|||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
struct Registers {
|
||||
struct IO {
|
||||
struct Layer {
|
||||
bool oneEnable;
|
||||
bool oneInvert;
|
||||
|
@ -31,7 +31,7 @@ struct Window {
|
|||
uint8 oneRight;
|
||||
uint8 twoLeft;
|
||||
uint8 twoRight;
|
||||
} r;
|
||||
} io;
|
||||
|
||||
struct Output {
|
||||
struct Pixel {
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
alwaysinline auto SMP::readRAM(uint16 addr) -> uint8 {
|
||||
if(addr >= 0xffc0 && status.iplromEnable) return iplrom[addr & 0x3f];
|
||||
if(status.ramDisable) return 0x5a; //0xff on mini-SNES
|
||||
if(addr >= 0xffc0 && io.iplromEnable) return iplrom[addr & 0x3f];
|
||||
if(io.ramDisable) return 0x5a; //0xff on mini-SNES
|
||||
return apuram[addr];
|
||||
}
|
||||
|
||||
alwaysinline auto SMP::writeRAM(uint16 addr, uint8 data) -> void {
|
||||
//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 {
|
||||
|
@ -28,24 +28,24 @@ auto SMP::readBus(uint16 addr) -> uint8 {
|
|||
return 0x00;
|
||||
|
||||
case 0xf2: //DSPADDR
|
||||
return status.dspAddr;
|
||||
return io.dspAddr;
|
||||
|
||||
case 0xf3: //DSPDATA
|
||||
//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 0xf5: //CPUIO1
|
||||
case 0xf6: //CPUIO2
|
||||
case 0xf7: //CPUIO3
|
||||
synchronizeCPU();
|
||||
return cpu.portRead(addr);
|
||||
return cpu.readPort(addr);
|
||||
|
||||
case 0xf8: //RAM0
|
||||
return status.ram00f8;
|
||||
return io.ram00f8;
|
||||
|
||||
case 0xf9: //RAM1
|
||||
return status.ram00f9;
|
||||
return io.ram00f9;
|
||||
|
||||
case 0xfa: //T0TARGET
|
||||
case 0xfb: //T1TARGET
|
||||
|
@ -76,14 +76,14 @@ auto SMP::writeBus(uint16 addr, uint8 data) -> void {
|
|||
case 0xf0: //TEST
|
||||
if(regs.p.p) break; //writes only valid when P flag is clear
|
||||
|
||||
status.clockSpeed = (data >> 6) & 3;
|
||||
status.timerSpeed = (data >> 4) & 3;
|
||||
status.timersEnable = data & 0x08;
|
||||
status.ramDisable = data & 0x04;
|
||||
status.ramWritable = data & 0x02;
|
||||
status.timersDisable = data & 0x01;
|
||||
io.clockSpeed = (data >> 6) & 3;
|
||||
io.timerSpeed = (data >> 4) & 3;
|
||||
io.timersEnable = data & 0x08;
|
||||
io.ramDisable = data & 0x04;
|
||||
io.ramWritable = data & 0x02;
|
||||
io.timersDisable = data & 0x01;
|
||||
|
||||
status.timerStep = (1 << status.clockSpeed) + (2 << status.timerSpeed);
|
||||
io.timerStep = (1 << io.clockSpeed) + (2 << io.timerSpeed);
|
||||
|
||||
timer0.synchronizeStage1();
|
||||
timer1.synchronizeStage1();
|
||||
|
@ -91,19 +91,19 @@ auto SMP::writeBus(uint16 addr, uint8 data) -> void {
|
|||
break;
|
||||
|
||||
case 0xf1: //CONTROL
|
||||
status.iplromEnable = data & 0x80;
|
||||
io.iplromEnable = data & 0x80;
|
||||
|
||||
if(data & 0x30) {
|
||||
//one-time clearing of APU port read registers,
|
||||
//emulated by simulating CPU writes of 0x00
|
||||
synchronizeCPU();
|
||||
if(data & 0x20) {
|
||||
cpu.portWrite(2, 0x00);
|
||||
cpu.portWrite(3, 0x00);
|
||||
cpu.writePort(2, 0x00);
|
||||
cpu.writePort(3, 0x00);
|
||||
}
|
||||
if(data & 0x10) {
|
||||
cpu.portWrite(0, 0x00);
|
||||
cpu.portWrite(1, 0x00);
|
||||
cpu.writePort(0, 0x00);
|
||||
cpu.writePort(1, 0x00);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -128,12 +128,12 @@ auto SMP::writeBus(uint16 addr, uint8 data) -> void {
|
|||
break;
|
||||
|
||||
case 0xf2: //DSPADDR
|
||||
status.dspAddr = data;
|
||||
io.dspAddr = data;
|
||||
break;
|
||||
|
||||
case 0xf3: //DSPDATA
|
||||
if(status.dspAddr & 0x80) break; //0x80-0xff are read-only mirrors of 0x00-0x7f
|
||||
dsp.write(status.dspAddr & 0x7f, data);
|
||||
if(io.dspAddr & 0x80) break; //0x80-0xff are read-only mirrors of 0x00-0x7f
|
||||
dsp.write(io.dspAddr & 0x7f, data);
|
||||
break;
|
||||
|
||||
case 0xf4: //CPUIO0
|
||||
|
@ -145,11 +145,11 @@ auto SMP::writeBus(uint16 addr, uint8 data) -> void {
|
|||
break;
|
||||
|
||||
case 0xf8: //RAM0
|
||||
status.ram00f8 = data;
|
||||
io.ram00f8 = data;
|
||||
break;
|
||||
|
||||
case 0xf9: //RAM1
|
||||
status.ram00f9 = data;
|
||||
io.ram00f9 = data;
|
||||
break;
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
auto SMP::io() -> void {
|
||||
addClocks(24);
|
||||
auto SMP::idle() -> void {
|
||||
step(24);
|
||||
cycleEdge();
|
||||
}
|
||||
|
||||
auto SMP::read(uint16 addr) -> uint8 {
|
||||
addClocks(12);
|
||||
step(12);
|
||||
uint8 data = readBus(addr);
|
||||
addClocks(12);
|
||||
step(12);
|
||||
cycleEdge();
|
||||
return data;
|
||||
}
|
||||
|
||||
auto SMP::write(uint16 addr, uint8 data) -> void {
|
||||
addClocks(24);
|
||||
step(24);
|
||||
writeBus(addr, data);
|
||||
cycleEdge();
|
||||
}
|
||||
|
||||
auto SMP::readDisassembler(uint16 addr) -> uint8 {
|
||||
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];
|
||||
}
|
||||
|
|
|
@ -4,23 +4,23 @@ auto SMP::serialize(serializer& s) -> void {
|
|||
|
||||
s.array(apuram);
|
||||
|
||||
s.integer(status.clockCounter);
|
||||
s.integer(status.dspCounter);
|
||||
s.integer(status.timerStep);
|
||||
s.integer(io.clockCounter);
|
||||
s.integer(io.dspCounter);
|
||||
s.integer(io.timerStep);
|
||||
|
||||
s.integer(status.clockSpeed);
|
||||
s.integer(status.timerSpeed);
|
||||
s.integer(status.timersEnable);
|
||||
s.integer(status.ramDisable);
|
||||
s.integer(status.ramWritable);
|
||||
s.integer(status.timersDisable);
|
||||
s.integer(io.clockSpeed);
|
||||
s.integer(io.timerSpeed);
|
||||
s.integer(io.timersEnable);
|
||||
s.integer(io.ramDisable);
|
||||
s.integer(io.ramWritable);
|
||||
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(status.ram00f9);
|
||||
s.integer(io.ram00f8);
|
||||
s.integer(io.ram00f9);
|
||||
|
||||
s.integer(timer0.stage0);
|
||||
s.integer(timer0.stage1);
|
||||
|
|
|
@ -8,11 +8,6 @@ SMP smp;
|
|||
#include "timing.cpp"
|
||||
#include "serialization.cpp"
|
||||
|
||||
auto SMP::step(uint clocks) -> void {
|
||||
clock += clocks * (uint64)cpu.frequency;
|
||||
dsp.clock -= clocks;
|
||||
}
|
||||
|
||||
auto SMP::synchronizeCPU() -> void {
|
||||
if(clock >= 0 && !scheduler.synchronizing()) co_switch(cpu.thread);
|
||||
}
|
||||
|
@ -63,27 +58,27 @@ auto SMP::reset() -> void {
|
|||
apuram[0x00f6] = 0x00;
|
||||
apuram[0x00f7] = 0x00;
|
||||
|
||||
status.clockCounter = 0;
|
||||
status.dspCounter = 0;
|
||||
status.timerStep = 3;
|
||||
io.clockCounter = 0;
|
||||
io.dspCounter = 0;
|
||||
io.timerStep = 3;
|
||||
|
||||
//$00f0
|
||||
status.clockSpeed = 0;
|
||||
status.timerSpeed = 0;
|
||||
status.timersEnable = true;
|
||||
status.ramDisable = false;
|
||||
status.ramWritable = true;
|
||||
status.timersDisable = false;
|
||||
io.clockSpeed = 0;
|
||||
io.timerSpeed = 0;
|
||||
io.timersEnable = true;
|
||||
io.ramDisable = false;
|
||||
io.ramWritable = true;
|
||||
io.timersDisable = false;
|
||||
|
||||
//$00f1
|
||||
status.iplromEnable = true;
|
||||
io.iplromEnable = true;
|
||||
|
||||
//$00f2
|
||||
status.dspAddr = 0x00;
|
||||
io.dspAddr = 0x00;
|
||||
|
||||
//$00f8,$00f9
|
||||
status.ram00f8 = 0x00;
|
||||
status.ram00f9 = 0x00;
|
||||
io.ram00f8 = 0x00;
|
||||
io.ram00f9 = 0x00;
|
||||
|
||||
timer0.stage0 = 0;
|
||||
timer1.stage0 = 0;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
//Sony CXP1100Q-1
|
||||
|
||||
struct SMP : Processor::SPC700, Thread {
|
||||
alwaysinline auto step(uint clocks) -> void;
|
||||
alwaysinline auto synchronizeCPU() -> void;
|
||||
alwaysinline auto synchronizeDSP() -> void;
|
||||
|
||||
|
@ -19,7 +18,7 @@ struct SMP : Processor::SPC700, Thread {
|
|||
uint8 apuram[64 * 1024];
|
||||
|
||||
privileged:
|
||||
struct {
|
||||
struct IO {
|
||||
//timing
|
||||
uint clockCounter;
|
||||
uint dspCounter;
|
||||
|
@ -42,7 +41,7 @@ privileged:
|
|||
//$00f8,$00f9
|
||||
uint8 ram00f8;
|
||||
uint8 ram00f9;
|
||||
} status;
|
||||
} io;
|
||||
|
||||
static auto Enter() -> void;
|
||||
|
||||
|
@ -53,15 +52,14 @@ privileged:
|
|||
auto readBus(uint16 addr) -> uint8;
|
||||
auto writeBus(uint16 addr, uint8 data) -> void;
|
||||
|
||||
auto io() -> void override;
|
||||
auto idle() -> void override;
|
||||
auto read(uint16 addr) -> uint8 override;
|
||||
auto write(uint16 addr, uint8 data) -> void override;
|
||||
|
||||
auto readDisassembler(uint16 addr) -> uint8 override;
|
||||
|
||||
//timing.cpp
|
||||
template<uint Frequency>
|
||||
struct Timer {
|
||||
template<uint Frequency> struct Timer {
|
||||
uint8 stage0;
|
||||
uint8 stage1;
|
||||
uint8 stage2;
|
||||
|
@ -78,7 +76,7 @@ privileged:
|
|||
Timer<192> timer1;
|
||||
Timer< 24> timer2;
|
||||
|
||||
alwaysinline auto addClocks(uint clocks) -> void;
|
||||
alwaysinline auto step(uint clocks) -> void;
|
||||
alwaysinline auto cycleEdge() -> void;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
auto SMP::addClocks(uint clocks) -> void {
|
||||
step(clocks);
|
||||
auto SMP::step(uint clocks) -> void {
|
||||
clock += clocks * (uint64)cpu.frequency;
|
||||
dsp.clock -= clocks;
|
||||
synchronizeDSP();
|
||||
|
||||
#if defined(DEBUGGER)
|
||||
|
@ -18,18 +19,17 @@ auto SMP::cycleEdge() -> void {
|
|||
|
||||
//TEST register S-SMP speed control
|
||||
//24 clocks have already been added for this cycle at this point
|
||||
switch(status.clockSpeed) {
|
||||
switch(io.clockSpeed) {
|
||||
case 0: break; //100% speed
|
||||
case 1: addClocks(24); break; // 50% speed
|
||||
case 2: while(true) addClocks(24); // 0% speed -- locks S-SMP
|
||||
case 3: addClocks(24 * 9); break; // 10% speed
|
||||
case 1: step(24); break; // 50% speed
|
||||
case 2: while(true) step(24); // 0% speed -- locks S-SMP
|
||||
case 3: step(24 * 9); break; // 10% speed
|
||||
}
|
||||
}
|
||||
|
||||
template<unsigned Frequency>
|
||||
auto SMP::Timer<Frequency>::tick() -> void {
|
||||
template<uint Frequency> auto SMP::Timer<Frequency>::tick() -> void {
|
||||
//stage 0 increment
|
||||
stage0 += smp.status.timerStep;
|
||||
stage0 += smp.io.timerStep;
|
||||
if(stage0 < Frequency) return;
|
||||
stage0 -= Frequency;
|
||||
|
||||
|
@ -38,18 +38,17 @@ auto SMP::Timer<Frequency>::tick() -> void {
|
|||
synchronizeStage1();
|
||||
}
|
||||
|
||||
template<unsigned Frequency>
|
||||
auto SMP::Timer<Frequency>::synchronizeStage1() -> void {
|
||||
template<uint Frequency> auto SMP::Timer<Frequency>::synchronizeStage1() -> void {
|
||||
bool newLine = stage1;
|
||||
if(smp.status.timersEnable == false) newLine = false;
|
||||
if(smp.status.timersDisable == true) newLine = false;
|
||||
if(!smp.io.timersEnable) newLine = false;
|
||||
if(smp.io.timersDisable) newLine = false;
|
||||
|
||||
bool oldLine = line;
|
||||
line = newLine;
|
||||
if(oldLine != 1 || newLine != 0) return; //only pulse on 1->0 transition
|
||||
|
||||
//stage 2 increment
|
||||
if(enable == false) return;
|
||||
if(!enable) return;
|
||||
if(++stage2 != target) return;
|
||||
|
||||
//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;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ struct Program : Emulator::Interface::Bind {
|
|||
auto audioSample(const double* samples, uint channels) -> void override;
|
||||
auto inputPoll(uint port, uint device, uint input) -> int16 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;
|
||||
|
||||
//medium.cpp
|
||||
|
|
|
@ -2,7 +2,7 @@ auto Program::stateName(uint slot, bool manager) -> string {
|
|||
return {
|
||||
mediumPaths(1), "higan/states/",
|
||||
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("+");
|
||||
for(auto& code : codes) {
|
||||
lstring part = code.split("/");
|
||||
if(part.size() == 2) cheat.append(hex(part[0]), hex(part[1]));
|
||||
if(part.size() == 3) cheat.append(hex(part[0]), hex(part[1]), hex(part[2]));
|
||||
if(part.size() == 2) cheat.append(part[0].hex(), part[1].hex());
|
||||
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 {
|
||||
return (uintptr)cocoaViewport;
|
||||
auto pViewport::handle() const -> uintptr_t {
|
||||
return (uintptr_t)cocoaViewport;
|
||||
}
|
||||
|
||||
auto pViewport::setDroppable(bool droppable) -> void {
|
||||
|
|
|
@ -18,7 +18,7 @@ namespace hiro {
|
|||
struct pViewport : pWidget {
|
||||
Declare(Viewport, Widget)
|
||||
|
||||
auto handle() const -> uintptr;
|
||||
auto handle() const -> uintptr_t;
|
||||
auto setDroppable(bool droppable) -> void;
|
||||
|
||||
CocoaViewport* cocoaViewport = nullptr;
|
||||
|
|
|
@ -193,7 +193,7 @@ auto pIconView::_updateSelected() -> void {
|
|||
while(p) {
|
||||
auto path = (GtkTreePath*)p->data;
|
||||
char* pathString = gtk_tree_path_to_string(path);
|
||||
unsigned position = natural(pathString);
|
||||
unsigned position = toNatural(pathString);
|
||||
g_free(pathString);
|
||||
selected.append(position);
|
||||
p = p->next;
|
||||
|
|
|
@ -218,7 +218,7 @@ auto pTableView::_doContext() -> void {
|
|||
|
||||
auto pTableView::_doDataFunc(GtkTreeViewColumn* gtkColumn, GtkCellRenderer* renderer, GtkTreeIter* iter) -> void {
|
||||
auto path = gtk_tree_model_get_string_from_iter(gtkTreeModel, iter);
|
||||
auto row = natural(path);
|
||||
auto row = toNatural(path);
|
||||
g_free(path);
|
||||
|
||||
if(auto& header = state().header) {
|
||||
|
@ -271,7 +271,7 @@ auto pTableView::_doEdit(GtkCellRendererText* gtkCellRendererText, const char* p
|
|||
for(auto& column : header->state.columns) {
|
||||
if(auto delegate = column->self()) {
|
||||
if(gtkCellRendererText == GTK_CELL_RENDERER_TEXT(delegate->gtkCellText)) {
|
||||
auto row = natural(path);
|
||||
auto row = toNatural(path);
|
||||
if(auto item = self().item(row)) {
|
||||
if(auto cell = item->cell(column->offset())) {
|
||||
if(string{text} != cell->state.text) {
|
||||
|
@ -343,7 +343,7 @@ auto pTableView::_doToggle(GtkCellRendererToggle* gtkCellRendererToggle, const c
|
|||
for(auto& column : header->state.columns) {
|
||||
if(auto delegate = column->self()) {
|
||||
if(gtkCellRendererToggle == GTK_CELL_RENDERER_TOGGLE(delegate->gtkCellToggle)) {
|
||||
auto row = natural(path);
|
||||
auto row = toNatural(path);
|
||||
if(auto item = self().item(row)) {
|
||||
if(auto cell = item->cell(column->offset())) {
|
||||
cell->setChecked(!cell->checked());
|
||||
|
@ -371,7 +371,7 @@ auto pTableView::_updateSelected() -> void {
|
|||
GtkTreeIter iter;
|
||||
if(gtk_tree_model_get_iter(gtkTreeModel, &iter, (GtkTreePath*)p->data)) {
|
||||
char* pathname = gtk_tree_model_get_string_from_iter(gtkTreeModel, &iter);
|
||||
unsigned selection = natural(pathname);
|
||||
unsigned selection = toNatural(pathname);
|
||||
g_free(pathname);
|
||||
selected.append(selection);
|
||||
}
|
||||
|
|
|
@ -4,83 +4,83 @@
|
|||
|
||||
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 (
|
||||
*s == '0' || *s == '1' ? binary_(s + 1, (sum << 1) | *s - '0') :
|
||||
*s == '\'' ? binary_(s + 1, sum) :
|
||||
*s == '0' || *s == '1' ? toBinary_(s + 1, (sum << 1) | *s - '0') :
|
||||
*s == '\'' ? toBinary_(s + 1, 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 (
|
||||
*s >= '0' && *s <= '7' ? octal_(s + 1, (sum << 3) | *s - '0') :
|
||||
*s == '\'' ? octal_(s + 1, sum) :
|
||||
*s >= '0' && *s <= '7' ? toOctal_(s + 1, (sum << 3) | *s - '0') :
|
||||
*s == '\'' ? toOctal_(s + 1, 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 (
|
||||
*s >= '0' && *s <= '9' ? decimal_(s + 1, (sum * 10) + *s - '0') :
|
||||
*s == '\'' ? decimal_(s + 1, sum) :
|
||||
*s >= '0' && *s <= '9' ? toDecimal_(s + 1, (sum * 10) + *s - '0') :
|
||||
*s == '\'' ? toDecimal_(s + 1, 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 (
|
||||
*s >= 'A' && *s <= 'F' ? hex_(s + 1, (sum << 4) | *s - 'A' + 10) :
|
||||
*s >= 'a' && *s <= 'f' ? hex_(s + 1, (sum << 4) | *s - 'a' + 10) :
|
||||
*s >= '0' && *s <= '9' ? hex_(s + 1, (sum << 4) | *s - '0') :
|
||||
*s == '\'' ? hex_(s + 1, sum) :
|
||||
*s >= 'A' && *s <= 'F' ? toHex_(s + 1, (sum << 4) | *s - 'A' + 10) :
|
||||
*s >= 'a' && *s <= 'f' ? toHex_(s + 1, (sum << 4) | *s - 'a' + 10) :
|
||||
*s >= '0' && *s <= '9' ? toHex_(s + 1, (sum << 4) | *s - '0') :
|
||||
*s == '\'' ? toHex_(s + 1, sum) :
|
||||
sum
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
constexpr inline auto binary(const char* s) -> uintmax {
|
||||
constexpr inline auto toBinary(const char* s) -> uintmax_t {
|
||||
return (
|
||||
*s == '0' && (*(s + 1) == 'B' || *(s + 1) == 'b') ? binary_(s + 2) :
|
||||
*s == '%' ? binary_(s + 1) : binary_(s)
|
||||
*s == '0' && (*(s + 1) == 'B' || *(s + 1) == 'b') ? toBinary_(s + 2) :
|
||||
*s == '%' ? toBinary_(s + 1) : toBinary_(s)
|
||||
);
|
||||
}
|
||||
|
||||
constexpr inline auto octal(const char* s) -> uintmax {
|
||||
constexpr inline auto toOctal(const char* s) -> uintmax_t {
|
||||
return (
|
||||
*s == '0' && (*(s + 1) == 'O' || *(s + 1) == 'o') ? octal_(s + 2) :
|
||||
octal_(s)
|
||||
*s == '0' && (*(s + 1) == 'O' || *(s + 1) == 'o') ? toOctal_(s + 2) :
|
||||
toOctal_(s)
|
||||
);
|
||||
}
|
||||
|
||||
constexpr inline auto hex(const char* s) -> uintmax {
|
||||
constexpr inline auto toHex(const char* s) -> uintmax_t {
|
||||
return (
|
||||
*s == '0' && (*(s + 1) == 'X' || *(s + 1) == 'x') ? hex_(s + 2) :
|
||||
*s == '$' ? hex_(s + 1) : hex_(s)
|
||||
*s == '0' && (*(s + 1) == 'X' || *(s + 1) == 'x') ? toHex_(s + 2) :
|
||||
*s == '$' ? toHex_(s + 1) : toHex_(s)
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
constexpr inline auto natural(const char* s) -> uintmax {
|
||||
constexpr inline auto toNatural(const char* s) -> uintmax_t {
|
||||
return (
|
||||
*s == '0' && (*(s + 1) == 'B' || *(s + 1) == 'b') ? binary_(s + 2) :
|
||||
*s == '0' && (*(s + 1) == 'O' || *(s + 1) == 'o') ? octal_(s + 2) :
|
||||
*s == '0' && (*(s + 1) == 'X' || *(s + 1) == 'x') ? hex_(s + 2) :
|
||||
*s == '%' ? binary_(s + 1) : *s == '$' ? hex_(s + 1) : decimal_(s)
|
||||
*s == '0' && (*(s + 1) == 'B' || *(s + 1) == 'b') ? toBinary_(s + 2) :
|
||||
*s == '0' && (*(s + 1) == 'O' || *(s + 1) == 'o') ? toOctal_(s + 2) :
|
||||
*s == '0' && (*(s + 1) == 'X' || *(s + 1) == 'x') ? toHex_(s + 2) :
|
||||
*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 (
|
||||
*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);
|
||||
}
|
||||
|
||||
|
|
32
nall/bit.hpp
32
nall/bit.hpp
|
@ -4,28 +4,28 @@
|
|||
|
||||
namespace nall {
|
||||
|
||||
template<uint bits> inline auto uclamp(const uintmax x) -> uintmax {
|
||||
enum : uintmax { b = 1ull << (bits - 1), y = b * 2 - 1 };
|
||||
template<uint bits> inline auto uclamp(const uintmax_t x) -> uintmax_t {
|
||||
enum : uintmax_t { b = 1ull << (bits - 1), y = b * 2 - 1 };
|
||||
return y + ((x - y) & -(x < y)); //min(x, y);
|
||||
}
|
||||
|
||||
template<uint bits> inline auto uclip(const uintmax x) -> uintmax {
|
||||
enum : uintmax { b = 1ull << (bits - 1), m = b * 2 - 1 };
|
||||
template<uint bits> inline auto uclip(const uintmax_t x) -> uintmax_t {
|
||||
enum : uintmax_t { b = 1ull << (bits - 1), m = b * 2 - 1 };
|
||||
return (x & m);
|
||||
}
|
||||
|
||||
template<uint bits> inline auto sclamp(const intmax x) -> intmax {
|
||||
enum : intmax { b = 1ull << (bits - 1), m = b - 1 };
|
||||
template<uint bits> inline auto sclamp(const intmax_t x) -> intmax_t {
|
||||
enum : intmax_t { b = 1ull << (bits - 1), m = b - 1 };
|
||||
return (x > m) ? m : (x < -b) ? -b : x;
|
||||
}
|
||||
|
||||
template<uint bits> inline auto sclip(const intmax x) -> intmax {
|
||||
enum : uintmax { b = 1ull << (bits - 1), m = b * 2 - 1 };
|
||||
template<uint bits> inline auto sclip(const intmax_t x) -> intmax_t {
|
||||
enum : uintmax_t { b = 1ull << (bits - 1), m = b * 2 - 1 };
|
||||
return ((x & m) ^ b) - b;
|
||||
}
|
||||
|
||||
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 (
|
||||
*s == '0' || *s == '1' ? mask(s + 1, (sum << 1) | 1) :
|
||||
*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 (
|
||||
*s == '0' || *s == '1' ? test(s + 1, (sum << 1) | (*s - '0')) :
|
||||
*s == ' ' || *s == '_' ? test(s + 1, sum) :
|
||||
|
@ -44,22 +44,22 @@ namespace bit {
|
|||
}
|
||||
|
||||
//lowest(0b1110) == 0b0010
|
||||
constexpr inline auto lowest(const uintmax x) -> uintmax {
|
||||
constexpr inline auto lowest(const uintmax_t x) -> uintmax_t {
|
||||
return x & -x;
|
||||
}
|
||||
|
||||
//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);
|
||||
}
|
||||
|
||||
//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);
|
||||
}
|
||||
|
||||
//count number of bits set in a byte
|
||||
inline auto count(uintmax x) -> uint {
|
||||
inline auto count(uintmax_t x) -> uint {
|
||||
uint count = 0;
|
||||
do count += x & 1; while(x >>= 1);
|
||||
return count;
|
||||
|
@ -67,7 +67,7 @@ namespace bit {
|
|||
|
||||
//return index of the first bit set (or zero of no bits are set)
|
||||
//first(0b1000) == 3
|
||||
inline auto first(uintmax x) -> uint {
|
||||
inline auto first(uintmax_t x) -> uint {
|
||||
uint first = 0;
|
||||
while(x) { if(x & 1) break; x >>= 1; first++; }
|
||||
return first;
|
||||
|
@ -75,7 +75,7 @@ namespace bit {
|
|||
|
||||
//round up to next highest single bit:
|
||||
//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;
|
||||
while(x & (x - 1)) x &= x - 1;
|
||||
return x << 1;
|
||||
|
|
|
@ -30,9 +30,9 @@ struct Node {
|
|||
auto set(const string& value) -> void {
|
||||
switch(type) {
|
||||
case Type::Boolean: *(bool*)data = (value != "false"); break;
|
||||
case Type::Integer: *(int*)data = integer(value); break;
|
||||
case Type::Natural: *(uint*)data = natural(value); break;
|
||||
case Type::Double: *(double*)data = real(value); break;
|
||||
case Type::Integer: *(int*)data = toInteger(value); break;
|
||||
case Type::Natural: *(uint*)data = toNatural(value); break;
|
||||
case Type::Double: *(double*)data = toReal(value); break;
|
||||
case Type::String: *(string*)data = value; break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,7 +61,7 @@ struct file : inode, varint {
|
|||
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)
|
||||
struct stat data;
|
||||
stat(filename, &data);
|
||||
|
@ -127,16 +127,16 @@ struct file : inode, varint {
|
|||
return buffer[(file_offset++) & buffer_mask];
|
||||
}
|
||||
|
||||
auto readl(uint length = 1) -> uintmax {
|
||||
uintmax data = 0;
|
||||
auto readl(uint length = 1) -> uintmax_t {
|
||||
uintmax_t data = 0;
|
||||
for(int i = 0; i < length; i++) {
|
||||
data |= (uintmax)read() << (i << 3);
|
||||
data |= (uintmax_t)read() << (i << 3);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
auto readm(uint length = 1) -> uintmax {
|
||||
uintmax data = 0;
|
||||
auto readm(uint length = 1) -> uintmax_t {
|
||||
uintmax_t data = 0;
|
||||
while(length--) {
|
||||
data <<= 8;
|
||||
data |= read();
|
||||
|
@ -164,14 +164,14 @@ struct file : inode, varint {
|
|||
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--) {
|
||||
write(data);
|
||||
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--) {
|
||||
write(data >> (i << 3));
|
||||
}
|
||||
|
@ -200,7 +200,7 @@ struct file : inode, varint {
|
|||
if(!fp) return; //file not open
|
||||
buffer_flush();
|
||||
|
||||
intmax req_offset = file_offset;
|
||||
intmax_t req_offset = file_offset;
|
||||
switch(index_) {
|
||||
case index::absolute: 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 return false;
|
||||
|
||||
setResponseType(natural(response));
|
||||
setResponseType(response.natural());
|
||||
|
||||
for(auto& header : headers) {
|
||||
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")) {
|
||||
chunkReceived = true;
|
||||
chunkLength = hex(chunk);
|
||||
chunkLength = chunk.hex();
|
||||
if(chunkLength == 0) break;
|
||||
chunk.reset();
|
||||
}
|
||||
|
|
|
@ -31,29 +31,29 @@ auto service::command(const string& name, const string& command) -> bool {
|
|||
" stop : stop service if it is running\n"
|
||||
" remove : remove semaphore lock if service crashed\n"
|
||||
" {value} : send custom command to service\n"
|
||||
"", format{name}), false;
|
||||
"", string_format{name}), false;
|
||||
|
||||
if(shared.open(name, 4096)) {
|
||||
if(command == "start") {
|
||||
print("[{0}] already started\n", format{name});
|
||||
print("[{0}] already started\n", string_format{name});
|
||||
} else if(command == "status") {
|
||||
print("[{0}] running\n", format{name});
|
||||
print("[{0}] running\n", string_format{name});
|
||||
}
|
||||
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));
|
||||
shared.release();
|
||||
}
|
||||
if(command == "remove") {
|
||||
shared.remove();
|
||||
print("[{0}] removed\n", format{name});
|
||||
print("[{0}] removed\n", string_format{name});
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if(command == "start") {
|
||||
if(shared.create(name, 4096)) {
|
||||
print("[{0}] started\n", format{name});
|
||||
print("[{0}] started\n", string_format{name});
|
||||
auto pid = fork();
|
||||
if(pid == 0) {
|
||||
signal(SIGHUP, SIG_IGN);
|
||||
|
@ -63,13 +63,13 @@ auto service::command(const string& name, const string& command) -> bool {
|
|||
}
|
||||
shared.close();
|
||||
} else {
|
||||
print("[{0}] start failed ({1})\n", format{name, strerror(errno)});
|
||||
print("[{0}] start failed ({1})\n", string_format{name, strerror(errno)});
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if(command == "status") {
|
||||
print("[{0}] stopped\n", format{name});
|
||||
print("[{0}] stopped\n", string_format{name});
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -79,15 +79,15 @@ template<uint Bits> struct Natural {
|
|||
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 clamp(uint bits) -> uintmax {
|
||||
const uintmax b = 1ull << (bits - 1);
|
||||
const uintmax m = b * 2 - 1;
|
||||
inline auto clamp(uint bits) -> uintmax_t {
|
||||
const uintmax_t b = 1ull << (bits - 1);
|
||||
const uintmax_t m = b * 2 - 1;
|
||||
return data < m ? data : m;
|
||||
}
|
||||
|
||||
inline auto clip(uint bits) -> uintmax {
|
||||
const uintmax b = 1ull << (bits - 1);
|
||||
const uintmax m = b * 2 - 1;
|
||||
inline auto clip(uint bits) -> uintmax_t {
|
||||
const uintmax_t b = 1ull << (bits - 1);
|
||||
const uintmax_t m = b * 2 - 1;
|
||||
return data & m;
|
||||
}
|
||||
|
||||
|
@ -161,15 +161,15 @@ template<uint Bits> struct Integer {
|
|||
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 clamp(uint bits) -> intmax {
|
||||
const intmax b = 1ull << (bits - 1);
|
||||
const intmax m = b - 1;
|
||||
inline auto clamp(uint bits) -> intmax_t {
|
||||
const intmax_t b = 1ull << (bits - 1);
|
||||
const intmax_t m = b - 1;
|
||||
return data > m ? m : data < -b ? -b : data;
|
||||
}
|
||||
|
||||
inline auto clip(uint bits) -> intmax {
|
||||
const uintmax b = 1ull << (bits - 1);
|
||||
const uintmax m = b * 2 - 1;
|
||||
inline auto clip(uint bits) -> intmax_t {
|
||||
const uintmax_t b = 1ull << (bits - 1);
|
||||
const uintmax_t m = b * 2 - 1;
|
||||
return ((data & m) ^ b) - b;
|
||||
}
|
||||
|
||||
|
@ -185,8 +185,8 @@ template<uint Bits> struct Real {
|
|||
using type =
|
||||
type_if<expression<Bits == 32>, float32_t,
|
||||
type_if<expression<Bits == 64>, float64_t,
|
||||
type_if<expression<Bits == 80>, float80_t,
|
||||
void>>>;
|
||||
//type_if<expression<Bits == 80>, float80_t,
|
||||
void>>;
|
||||
|
||||
inline Real() : data(0.0) {}
|
||||
template<typename T> inline Real(const T& value) : data((type)value) {}
|
||||
|
@ -215,9 +215,8 @@ private:
|
|||
}
|
||||
|
||||
using boolean = nall::Boolean;
|
||||
//note: these conflict with nall/atoi.hpp functions
|
||||
//using integer = nall::Integer<sizeof( int) * 8>;
|
||||
//using natural = nall::Natural<sizeof(uint) * 8>;
|
||||
using integer = nall::Integer<sizeof( int) * 8>;
|
||||
using natural = nall::Natural<sizeof(uint) * 8>;
|
||||
|
||||
using int1 = nall::Integer< 1>;
|
||||
using int2 = nall::Integer< 2>;
|
||||
|
@ -351,4 +350,4 @@ using uint64 = nall::Natural<64>;
|
|||
|
||||
using float32 = nall::Real<32>;
|
||||
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& {
|
||||
enum { size = std::is_same<bool, T>::value ? 1 : sizeof(T) };
|
||||
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) {
|
||||
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) {
|
||||
_size += size;
|
||||
}
|
||||
|
|
|
@ -33,7 +33,8 @@
|
|||
|
||||
using float32_t = float;
|
||||
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(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(double) >= 8, "float64_t is not of the correct size");
|
||||
static_assert(sizeof(long double) >= 10, "float80_t is not of the correct size");
|
||||
|
||||
using intmax = intmax_t;
|
||||
using intptr = intptr_t;
|
||||
|
||||
using uintmax = uintmax_t;
|
||||
using uintptr = uintptr_t;
|
||||
//static_assert(sizeof(long double) >= 10, "float80_t is not of the correct size");
|
||||
|
||||
using uint = unsigned int;
|
||||
|
|
|
@ -24,8 +24,12 @@
|
|||
namespace nall {
|
||||
|
||||
struct string;
|
||||
struct format;
|
||||
struct lstring;
|
||||
struct string_view;
|
||||
struct string_vector;
|
||||
struct string_format;
|
||||
|
||||
//legacy naming convention
|
||||
using lstring = string_vector;
|
||||
|
||||
struct string_view {
|
||||
inline string_view();
|
||||
|
@ -61,18 +65,19 @@ template<typename T> struct stringify;
|
|||
//format.hpp
|
||||
template<typename... P> inline auto print(P&&...) -> void;
|
||||
template<typename... P> inline auto print(FILE*, P&&...) -> void;
|
||||
inline auto integer(intmax value, long precision = 0, char padchar = '0') -> string;
|
||||
inline auto natural(uintmax value, long precision = 0, char padchar = '0') -> string;
|
||||
inline auto hex(uintmax value, long precision = 0, char padchar = '0') -> string;
|
||||
inline auto octal(uintmax value, long precision = 0, char padchar = '0') -> string;
|
||||
inline auto binary(uintmax value, long precision = 0, char padchar = '0') -> string;
|
||||
template<typename T> inline auto numeral(T value, long precision = 0, char padchar = '0') -> string;
|
||||
//inline auto integer(intmax_t value, long precision = 0, char padchar = '0') -> string;
|
||||
//inline auto natural(uintmax_t value, long precision = 0, char padchar = '0') -> string;
|
||||
inline auto hex(uintmax_t 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;
|
||||
inline auto pointer(uintptr value, long precision = 0) -> string;
|
||||
inline auto real(long double value) -> string;
|
||||
inline auto pointer(uintptr_t value, long precision = 0) -> string;
|
||||
//inline auto real(long double value) -> string;
|
||||
|
||||
//match.hpp
|
||||
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
|
||||
inline auto pathname(string_view self) -> string;
|
||||
|
@ -85,10 +90,9 @@ inline auto suffixname(string_view self) -> string;
|
|||
|
||||
//utility.hpp
|
||||
inline auto slice(string_view self, int offset = 0, int length = -1) -> string;
|
||||
|
||||
inline auto integer(char* result, intmax value) -> char*;
|
||||
inline auto natural(char* result, uintmax value) -> char*;
|
||||
inline auto real(char* str, long double value) -> uint;
|
||||
inline auto fromInteger(char* result, intmax_t value) -> char*;
|
||||
inline auto fromNatural(char* result, uintmax_t value) -> char*;
|
||||
inline auto fromReal(char* str, long double value) -> uint;
|
||||
|
||||
struct string {
|
||||
using type = string;
|
||||
|
@ -179,15 +183,16 @@ public:
|
|||
auto end() const -> const char* { return &data()[size()]; }
|
||||
|
||||
//atoi.hpp
|
||||
inline auto integer() const -> intmax;
|
||||
inline auto natural() const -> uintmax;
|
||||
inline auto integer() const -> intmax_t;
|
||||
inline auto natural() const -> uintmax_t;
|
||||
inline auto hex() const -> uintmax_t;
|
||||
inline auto real() const -> double;
|
||||
|
||||
//core.hpp
|
||||
inline auto operator[](int) const -> const char&;
|
||||
template<typename... P> inline auto assign(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&;
|
||||
template<typename T> inline auto _append(const stringify<T>&) -> string&;
|
||||
inline auto length() const -> uint;
|
||||
|
@ -209,7 +214,7 @@ public:
|
|||
inline auto ifindFrom(int offset, string_view source) const -> maybe<uint>;
|
||||
|
||||
//format.hpp
|
||||
inline auto format(const nall::format& params) -> type&;
|
||||
inline auto format(const nall::string_format& params) -> type&;
|
||||
|
||||
//compare.hpp
|
||||
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&;
|
||||
|
||||
//split.hpp
|
||||
inline auto split(string_view key, long limit = LONG_MAX) const -> lstring;
|
||||
inline auto isplit(string_view key, long limit = LONG_MAX) const -> lstring;
|
||||
inline auto qsplit(string_view key, long limit = LONG_MAX) const -> lstring;
|
||||
inline auto iqsplit(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 -> string_vector;
|
||||
inline auto qsplit(string_view key, long limit = LONG_MAX) const -> string_vector;
|
||||
inline auto iqsplit(string_view key, long limit = LONG_MAX) const -> string_vector;
|
||||
|
||||
//trim.hpp
|
||||
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&;
|
||||
};
|
||||
|
||||
struct lstring : vector<string> {
|
||||
using type = lstring;
|
||||
struct string_vector : vector<string> {
|
||||
using type = string_vector;
|
||||
|
||||
lstring(const lstring& source) { vector::operator=(source); }
|
||||
lstring(lstring& source) { vector::operator=(source); }
|
||||
lstring(lstring&& source) { vector::operator=(move(source)); }
|
||||
template<typename... P> lstring(P&&... p) { append(forward<P>(p)...); }
|
||||
string_vector(const string_vector& source) { vector::operator=(source); }
|
||||
string_vector(string_vector& source) { vector::operator=(source); }
|
||||
string_vector(string_vector&& source) { vector::operator=(move(source)); }
|
||||
template<typename... P> string_vector(P&&... p) { append(forward<P>(p)...); }
|
||||
|
||||
//list.hpp
|
||||
inline auto operator==(const lstring&) const -> bool;
|
||||
inline auto operator!=(const lstring&) const -> bool;
|
||||
inline auto operator==(const string_vector&) 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=(lstring& source) -> type& { return vector::operator=(source), *this; }
|
||||
inline auto operator=(lstring&& source) -> type& { return vector::operator=(move(source)), *this; }
|
||||
inline auto operator=(const string_vector& source) -> type& { return vector::operator=(source), *this; }
|
||||
inline auto operator=(string_vector& source) -> type& { return vector::operator=(source), *this; }
|
||||
inline auto operator=(string_vector&& source) -> type& { return vector::operator=(move(source)), *this; }
|
||||
|
||||
inline auto isort() -> type&;
|
||||
|
||||
|
@ -301,18 +306,18 @@ struct lstring : vector<string> {
|
|||
|
||||
inline auto find(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 strip() -> type&;
|
||||
|
||||
//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> {
|
||||
using type = format;
|
||||
struct string_format : vector<string> {
|
||||
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&;
|
||||
inline auto append() -> type&;
|
||||
};
|
||||
|
|
|
@ -2,16 +2,20 @@
|
|||
|
||||
namespace nall {
|
||||
|
||||
auto string::integer() const -> intmax {
|
||||
return nall::integer(data());
|
||||
auto string::integer() const -> intmax_t {
|
||||
return toInteger(data());
|
||||
}
|
||||
|
||||
auto string::natural() const -> uintmax {
|
||||
return nall::natural(data());
|
||||
auto string::natural() const -> uintmax_t {
|
||||
return toNatural(data());
|
||||
}
|
||||
|
||||
auto string::hex() const -> uintmax_t {
|
||||
return toHex(data());
|
||||
}
|
||||
|
||||
auto string::real() const -> double {
|
||||
return nall::real(data());
|
||||
return toReal(data());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -33,42 +33,42 @@ template<> struct stringify<char> {
|
|||
//signed integers
|
||||
|
||||
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 size() const -> uint { return strlen(_data); }
|
||||
char _data[2 + sizeof(signed char) * 3];
|
||||
};
|
||||
|
||||
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 size() const -> uint { return strlen(_data); }
|
||||
char _data[2 + sizeof(signed short) * 3];
|
||||
};
|
||||
|
||||
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 size() const -> uint { return strlen(_data); }
|
||||
char _data[2 + sizeof(signed int) * 3];
|
||||
};
|
||||
|
||||
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 size() const -> uint { return strlen(_data); }
|
||||
char _data[2 + sizeof(signed long) * 3];
|
||||
};
|
||||
|
||||
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 size() const -> uint { return strlen(_data); }
|
||||
char _data[2 + sizeof(signed long long) * 3];
|
||||
};
|
||||
|
||||
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 size() const -> uint { return strlen(_data); }
|
||||
char _data[2 + sizeof(int64_t) * 3];
|
||||
|
@ -77,42 +77,42 @@ template<uint Bits> struct stringify<Integer<Bits>> {
|
|||
//unsigned integers
|
||||
|
||||
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 size() const -> uint { return strlen(_data); }
|
||||
char _data[1 + sizeof(unsigned char) * 3];
|
||||
};
|
||||
|
||||
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 size() const -> uint { return strlen(_data); }
|
||||
char _data[1 + sizeof(unsigned short) * 3];
|
||||
};
|
||||
|
||||
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 size() const -> uint { return strlen(_data); }
|
||||
char _data[1 + sizeof(unsigned int) * 3];
|
||||
};
|
||||
|
||||
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 size() const -> uint { return strlen(_data); }
|
||||
char _data[1 + sizeof(unsigned long) * 3];
|
||||
};
|
||||
|
||||
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 size() const -> uint { return strlen(_data); }
|
||||
char _data[1 + sizeof(unsigned long long) * 3];
|
||||
};
|
||||
|
||||
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 size() const -> uint { return strlen(_data); }
|
||||
char _data[1 + sizeof(uint64_t) * 3];
|
||||
|
@ -121,28 +121,28 @@ template<uint Bits> struct stringify<Natural<Bits>> {
|
|||
//floating-point
|
||||
|
||||
template<> struct stringify<float> {
|
||||
stringify(float source) { real(_data, source); }
|
||||
stringify(float source) { fromReal(_data, source); }
|
||||
auto data() const -> const char* { return _data; }
|
||||
auto size() const -> uint { return strlen(_data); }
|
||||
char _data[256];
|
||||
};
|
||||
|
||||
template<> struct stringify<double> {
|
||||
stringify(double source) { real(_data, source); }
|
||||
stringify(double source) { fromReal(_data, source); }
|
||||
auto data() const -> const char* { return _data; }
|
||||
auto size() const -> uint { return strlen(_data); }
|
||||
char _data[256];
|
||||
};
|
||||
|
||||
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 size() const -> uint { return strlen(_data); }
|
||||
char _data[256];
|
||||
};
|
||||
|
||||
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 size() const -> uint { return strlen(_data); }
|
||||
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)...);
|
||||
}
|
||||
|
||||
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);
|
||||
return append(forward<P>(p)...);
|
||||
}
|
||||
|
|
|
@ -6,9 +6,9 @@ auto string::date(time_t timestamp) -> string {
|
|||
if(timestamp == 0) timestamp = ::time(nullptr);
|
||||
tm* info = localtime(×tamp);
|
||||
return {
|
||||
nall::natural(1900 + info->tm_year, 4L), "-",
|
||||
nall::natural(1 + info->tm_mon, 2L), "-",
|
||||
nall::natural(info->tm_mday, 2L)
|
||||
numeral(1900 + info->tm_year, 4L), "-",
|
||||
numeral(1 + info->tm_mon, 2L), "-",
|
||||
numeral(info->tm_mday, 2L)
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -16,9 +16,9 @@ auto string::time(time_t timestamp) -> string {
|
|||
if(timestamp == 0) timestamp = ::time(nullptr);
|
||||
tm* info = localtime(×tamp);
|
||||
return {
|
||||
nall::natural(info->tm_hour, 2L), ":",
|
||||
nall::natural(info->tm_min, 2L), ":",
|
||||
nall::natural(info->tm_sec, 2L)
|
||||
numeral(info->tm_hour, 2L), ":",
|
||||
numeral(info->tm_min, 2L), ":",
|
||||
numeral(info->tm_sec, 2L)
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ inline auto evaluateExpression(Node* node) -> string {
|
|||
}
|
||||
|
||||
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])
|
||||
switch(node->type) {
|
||||
|
@ -99,7 +99,7 @@ inline auto integer(const string& expression) -> maybe<int64_t> {
|
|||
}
|
||||
|
||||
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])
|
||||
switch(node->type) {
|
||||
|
|
|
@ -5,7 +5,7 @@ namespace nall {
|
|||
//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
|
||||
|
||||
auto string::format(const nall::format& params) -> type& {
|
||||
auto string::format(const nall::string_format& params) -> type& {
|
||||
auto size = (int)this->size();
|
||||
auto data = (char*)memory::allocate(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; }
|
||||
|
||||
uint index = nall::natural(&data[x + 1]);
|
||||
uint index = toNatural(&data[x + 1]);
|
||||
if(index >= params.size()) { x++; continue; }
|
||||
|
||||
uint sourceSize = y - x;
|
||||
|
@ -59,12 +59,12 @@ auto string::format(const nall::format& params) -> type& {
|
|||
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);
|
||||
return append(forward<P>(p)...);
|
||||
}
|
||||
|
||||
auto format::append() -> format& {
|
||||
auto string_format::append() -> string_format& {
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -78,9 +78,10 @@ template<typename... P> auto print(FILE* fp, P&&... p) -> void {
|
|||
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;
|
||||
buffer.resize(1 + sizeof(intmax) * 3);
|
||||
buffer.resize(1 + sizeof(intmax_t) * 3);
|
||||
char* p = buffer.get();
|
||||
|
||||
bool negative = value < 0;
|
||||
|
@ -97,9 +98,9 @@ auto integer(intmax value, long precision, char padchar) -> string {
|
|||
return buffer;
|
||||
}
|
||||
|
||||
auto natural(uintmax value, long precision, char padchar) -> string {
|
||||
auto natural(uintmax_t value, long precision, char padchar) -> string {
|
||||
string buffer;
|
||||
buffer.resize(sizeof(uintmax) * 3);
|
||||
buffer.resize(sizeof(uintmax_t) * 3);
|
||||
char* p = buffer.get();
|
||||
|
||||
uint size = 0;
|
||||
|
@ -112,10 +113,17 @@ auto natural(uintmax value, long precision, char padchar) -> string {
|
|||
if(precision) buffer.size(precision, padchar);
|
||||
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;
|
||||
buffer.resize(sizeof(uintmax) * 2);
|
||||
buffer.resize(sizeof(uintmax_t) * 2);
|
||||
char* p = buffer.get();
|
||||
|
||||
uint size = 0;
|
||||
|
@ -130,9 +138,9 @@ auto hex(uintmax value, long precision, char padchar) -> string {
|
|||
return buffer;
|
||||
}
|
||||
|
||||
auto octal(uintmax value, long precision, char padchar) -> string {
|
||||
auto octal(uintmax_t value, long precision, char padchar) -> string {
|
||||
string buffer;
|
||||
buffer.resize(sizeof(uintmax) * 3);
|
||||
buffer.resize(sizeof(uintmax_t) * 3);
|
||||
char* p = buffer.get();
|
||||
|
||||
uint size = 0;
|
||||
|
@ -146,9 +154,9 @@ auto octal(uintmax value, long precision, char padchar) -> string {
|
|||
return buffer;
|
||||
}
|
||||
|
||||
auto binary(uintmax value, long precision, char padchar) -> string {
|
||||
auto binary(uintmax_t value, long precision, char padchar) -> string {
|
||||
string buffer;
|
||||
buffer.resize(sizeof(uintmax) * 8);
|
||||
buffer.resize(sizeof(uintmax_t) * 8);
|
||||
char* p = buffer.get();
|
||||
|
||||
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 {
|
||||
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)";
|
||||
return {"0x", hex(value, precision)};
|
||||
}
|
||||
|
||||
/*
|
||||
auto real(long double value) -> string {
|
||||
string temp;
|
||||
temp.resize(real(nullptr, value));
|
||||
real(temp.get(), value);
|
||||
temp.resize(fromReal(nullptr, value));
|
||||
fromReal(temp.get(), value);
|
||||
return temp;
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
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(size() != source.size()) return false;
|
||||
for(uint n = 0; n < size(); n++) {
|
||||
|
@ -11,50 +11,50 @@ auto lstring::operator==(const lstring& source) const -> bool {
|
|||
return true;
|
||||
}
|
||||
|
||||
auto lstring::operator!=(const lstring& source) const -> bool {
|
||||
auto string_vector::operator!=(const string_vector& source) const -> bool {
|
||||
return !operator==(source);
|
||||
}
|
||||
|
||||
auto lstring::isort() -> lstring& {
|
||||
auto string_vector::isort() -> type& {
|
||||
sort([](const string& x, const string& y) {
|
||||
return memory::icompare(x.data(), x.size(), y.data(), y.size()) < 0;
|
||||
});
|
||||
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);
|
||||
append(forward<P>(p)...);
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto lstring::append() -> lstring& {
|
||||
auto string_vector::append() -> type& {
|
||||
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++) {
|
||||
if(operator[](n).equals(source)) return n;
|
||||
}
|
||||
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++) {
|
||||
if(operator[](n).iequals(source)) return n;
|
||||
}
|
||||
return nothing;
|
||||
}
|
||||
|
||||
auto lstring::match(string_view pattern) const -> lstring {
|
||||
lstring result;
|
||||
auto string_vector::match(string_view pattern) const -> type {
|
||||
string_vector result;
|
||||
for(uint n = 0; n < size(); n++) {
|
||||
if(operator[](n).match(pattern)) result.append(operator[](n));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
auto lstring::merge(string_view separator) const -> string {
|
||||
auto string_vector::merge(string_view separator) const -> string {
|
||||
string output;
|
||||
for(uint n = 0; n < size(); n++) {
|
||||
output.append(operator[](n));
|
||||
|
@ -63,7 +63,7 @@ auto lstring::merge(string_view separator) const -> string {
|
|||
return output;
|
||||
}
|
||||
|
||||
auto lstring::strip() -> lstring& {
|
||||
auto string_vector::strip() -> type& {
|
||||
for(uint n = 0; n < size(); n++) {
|
||||
operator[](n).strip();
|
||||
}
|
||||
|
|
|
@ -59,8 +59,8 @@ struct Node {
|
|||
|
||||
auto text() const -> string { return value().strip(); }
|
||||
auto boolean() const -> bool { return text() == "true"; }
|
||||
auto integer() const -> intmax { return text().integer(); }
|
||||
auto natural() const -> uintmax { return text().natural(); }
|
||||
auto integer() const -> intmax_t { return text().integer(); }
|
||||
auto natural() const -> uintmax_t { return text().natural(); }
|
||||
auto real() const -> double { return text().real(); }
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
if(*p == '*') {
|
||||
const char* b = s;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
namespace nall {
|
||||
|
||||
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();
|
||||
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;
|
||||
}
|
||||
|
||||
auto string::split(string_view on, long limit) const -> lstring { return lstring()._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::qsplit(string_view on, long limit) const -> lstring { return lstring()._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::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 -> string_vector { return string_vector()._split<1, 0>(*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 -> 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;
|
||||
}
|
||||
|
||||
auto integer(char* result, intmax value) -> char* {
|
||||
auto fromInteger(char* result, intmax_t value) -> char* {
|
||||
bool negative = value < 0;
|
||||
if(negative) value = -value;
|
||||
|
||||
|
@ -111,7 +111,7 @@ auto integer(char* result, intmax value) -> char* {
|
|||
return result;
|
||||
}
|
||||
|
||||
auto natural(char* result, uintmax value) -> char* {
|
||||
auto fromNatural(char* result, uintmax_t value) -> char* {
|
||||
char buffer[64];
|
||||
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
|
||||
//a double to a string ... but attempting to parse a double by
|
||||
//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];
|
||||
#ifdef _WIN32
|
||||
//Windows C-runtime does not support long double via sprintf()
|
||||
|
|
|
@ -19,13 +19,13 @@ namespace nall {
|
|||
struct thread {
|
||||
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 exit() -> void;
|
||||
|
||||
struct context {
|
||||
function<auto (uintptr) -> void> callback;
|
||||
uintptr parameter = 0;
|
||||
function<auto (uintptr_t) -> void> callback;
|
||||
uintptr_t parameter = 0;
|
||||
};
|
||||
|
||||
private:
|
||||
|
@ -43,7 +43,7 @@ auto thread::join() -> void {
|
|||
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;
|
||||
|
||||
auto context = new thread::context;
|
||||
|
@ -76,13 +76,13 @@ struct thread {
|
|||
inline ~thread();
|
||||
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 exit() -> void;
|
||||
|
||||
struct context {
|
||||
function<auto (uintptr) -> void> callback;
|
||||
uintptr parameter = 0;
|
||||
function<auto (uintptr_t) -> void> callback;
|
||||
uintptr_t parameter = 0;
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
auto context = new thread::context;
|
||||
|
|
|
@ -10,8 +10,8 @@ struct varint {
|
|||
virtual auto read() -> uint8_t = 0;
|
||||
virtual auto write(uint8_t) -> void = 0;
|
||||
|
||||
auto readvu() -> uintmax {
|
||||
uintmax data = 0, shift = 1;
|
||||
auto readvu() -> uintmax_t {
|
||||
uintmax_t data = 0, shift = 1;
|
||||
while(true) {
|
||||
uint8_t x = read();
|
||||
data += (x & 0x7f) * shift;
|
||||
|
@ -22,15 +22,15 @@ struct varint {
|
|||
return data;
|
||||
}
|
||||
|
||||
auto readvs() -> intmax {
|
||||
uintmax data = readvu();
|
||||
auto readvs() -> intmax_t {
|
||||
uintmax_t data = readvu();
|
||||
bool negate = data & 1;
|
||||
data >>= 1;
|
||||
if(negate) data = ~data;
|
||||
return data;
|
||||
}
|
||||
|
||||
auto writevu(uintmax data) -> void {
|
||||
auto writevu(uintmax_t data) -> void {
|
||||
while(true) {
|
||||
uint8_t x = data & 0x7f;
|
||||
data >>= 7;
|
||||
|
@ -40,7 +40,7 @@ struct varint {
|
|||
}
|
||||
}
|
||||
|
||||
auto writevs(intmax data) -> void {
|
||||
auto writevs(intmax_t data) -> void {
|
||||
bool negate = data < 0;
|
||||
if(negate) data = ~data;
|
||||
data = (data << 1) | negate;
|
||||
|
|
|
@ -11,15 +11,15 @@ struct file : vfs::file {
|
|||
return instance;
|
||||
}
|
||||
|
||||
auto size() const -> uintmax override {
|
||||
auto size() const -> uintmax_t override {
|
||||
return _fp.size();
|
||||
}
|
||||
|
||||
auto offset() const -> uintmax override {
|
||||
auto offset() const -> uintmax_t override {
|
||||
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_);
|
||||
}
|
||||
|
||||
|
|
|
@ -5,18 +5,18 @@ namespace nall { namespace vfs { namespace memory {
|
|||
struct file : vfs::file {
|
||||
~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};
|
||||
instance->_open(data, size);
|
||||
return instance;
|
||||
}
|
||||
|
||||
auto size() const -> uintmax override { return _size; }
|
||||
auto offset() const -> uintmax override { return _offset; }
|
||||
auto size() const -> uintmax_t override { return _size; }
|
||||
auto offset() const -> uintmax_t override { return _offset; }
|
||||
|
||||
auto seek(intmax offset, index mode) -> void override {
|
||||
if(mode == index::absolute) _offset = (uintmax)offset;
|
||||
if(mode == index::relative) _offset += (intmax)offset;
|
||||
auto seek(intmax_t offset, index mode) -> void override {
|
||||
if(mode == index::absolute) _offset = (uintmax_t)offset;
|
||||
if(mode == index::relative) _offset += (intmax_t)offset;
|
||||
}
|
||||
|
||||
auto read() -> uint8_t override {
|
||||
|
@ -34,15 +34,15 @@ private:
|
|||
file(const 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;
|
||||
_data = new uint8_t[size];
|
||||
nall::memory::copy(_data, data, size);
|
||||
}
|
||||
|
||||
uint8_t* _data = nullptr;
|
||||
uintmax _size = 0;
|
||||
uintmax _offset = 0;
|
||||
uintmax_t _size = 0;
|
||||
uintmax_t _offset = 0;
|
||||
};
|
||||
|
||||
}}}
|
||||
|
|
|
@ -11,10 +11,10 @@ struct file {
|
|||
|
||||
virtual ~file() = default;
|
||||
|
||||
virtual auto size() const -> uintmax = 0;
|
||||
virtual auto offset() const -> uintmax = 0;
|
||||
virtual auto size() const -> uintmax_t = 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 write(uint8_t data) -> void = 0;
|
||||
virtual auto flush() -> void {}
|
||||
|
@ -23,19 +23,19 @@ struct file {
|
|||
return offset() >= size();
|
||||
}
|
||||
|
||||
auto read(void* vdata, uintmax bytes) -> void {
|
||||
auto read(void* vdata, uintmax_t bytes) -> void {
|
||||
auto data = (uint8_t*)vdata;
|
||||
while(bytes--) *data++ = read();
|
||||
}
|
||||
|
||||
auto readl(uint bytes) -> uintmax {
|
||||
uintmax data = 0;
|
||||
for(auto n : range(bytes)) data |= (uintmax)read() << n * 8;
|
||||
auto readl(uint bytes) -> uintmax_t {
|
||||
uintmax_t data = 0;
|
||||
for(auto n : range(bytes)) data |= (uintmax_t)read() << n * 8;
|
||||
return data;
|
||||
}
|
||||
|
||||
auto readm(uint bytes) -> uintmax {
|
||||
uintmax data = 0;
|
||||
auto readm(uint bytes) -> uintmax_t {
|
||||
uintmax_t data = 0;
|
||||
for(auto n : range(bytes)) data = data << 8 | read();
|
||||
return data;
|
||||
}
|
||||
|
@ -47,16 +47,16 @@ struct file {
|
|||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
auto writem(uintmax data, uint bytes) -> void {
|
||||
auto writem(uintmax_t data, uint bytes) -> void {
|
||||
for(auto n : rrange(bytes)) write(data >> n * 8);
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ struct InputXlib : Input {
|
|||
~InputXlib() { term(); }
|
||||
|
||||
struct Settings {
|
||||
uintptr handle = 0;
|
||||
uintptr_t handle = 0;
|
||||
} settings;
|
||||
|
||||
auto cap(const string& name) -> bool {
|
||||
|
@ -29,8 +29,8 @@ struct InputXlib : Input {
|
|||
}
|
||||
|
||||
auto set(const string& name, const any& value) -> bool {
|
||||
if(name == Input::Handle && value.is<uintptr>()) {
|
||||
settings.handle = value.get<uintptr>();
|
||||
if(name == Input::Handle && value.is<uintptr_t>()) {
|
||||
settings.handle = value.get<uintptr_t>();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -32,15 +32,15 @@ struct VideoCGL : Video, OpenGL {
|
|||
}
|
||||
|
||||
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::Filter) return settings.filter;
|
||||
return {};
|
||||
}
|
||||
|
||||
auto set(const string& name, const any& value) -> bool {
|
||||
if(name == Video::Handle && value.is<uintptr>()) {
|
||||
settings.handle = (NSView*)value.get<uintptr>();
|
||||
if(name == Video::Handle && value.is<uintptr_t>()) {
|
||||
settings.handle = (NSView*)value.get<uintptr_t>();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,11 +28,11 @@ auto OpenGL::shader(const string& pathname) -> void {
|
|||
for(auto node : document["output"]) {
|
||||
string text = node.text();
|
||||
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();
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,9 +4,9 @@ auto OpenGLProgram::bind(OpenGL* instance, const Markup::Node& node, const strin
|
|||
modulo = glrModulo(node["modulo"].integer());
|
||||
|
||||
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();
|
||||
if(h.endsWith("%")) relativeHeight = real(h.trimRight("%", 1L)) / 100.0;
|
||||
if(h.endsWith("%")) relativeHeight = toReal(h.trimRight("%", 1L)) / 100.0;
|
||||
else absoluteHeight = h.natural();
|
||||
|
||||
format = glrFormat(node["format"].text());
|
||||
|
|
|
@ -30,15 +30,15 @@ struct VideoWGL : Video, OpenGL {
|
|||
}
|
||||
|
||||
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::Filter) return settings.filter;
|
||||
return {};
|
||||
}
|
||||
|
||||
auto set(const string& name, const any& value) -> bool {
|
||||
if(name == Video::Handle && value.is<uintptr>()) {
|
||||
settings.handle = (HWND)value.get<uintptr>();
|
||||
if(name == Video::Handle && value.is<uintptr_t>()) {
|
||||
settings.handle = (HWND)value.get<uintptr_t>();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue