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:
Tim Allen 2016-07-01 21:50:32 +10:00
parent 67457fade4
commit 82293c95ae
89 changed files with 1545 additions and 1594 deletions

View File

@ -11,42 +11,17 @@ using namespace nall;
namespace Emulator { namespace Emulator {
static const string Name = "higan"; static const string Name = "higan";
static const string Version = "099.13"; static const string Version = "099.14";
static const string Author = "byuu"; static const string Author = "byuu";
static const string License = "GPLv3"; static const string License = "GPLv3";
static const string Website = "http://byuu.org/"; static const string Website = "http://byuu.org/";
//incremented only when serialization format changes //incremented only when serialization format changes
static const string SerializerVersion = "099.07"; static const string SerializerVersion = "099.14";
} }
#include "interface.hpp" #include "interface.hpp"
//debugging function hook:
//no overhead (and no debugger invocation) if not compiled with -DDEBUGGER
//wraps testing of function to allow invocation without a defined callback
template<typename T> struct hook;
template<typename R, typename... P> struct hook<auto (P...) -> R> {
function<auto (P...) -> R> callback;
auto operator()(P... p) const -> R {
#if defined(DEBUGGER)
if(callback) return callback(forward<P>(p)...);
#endif
return R();
}
hook() {}
hook(const hook& hook) { callback = hook.callback; }
hook(void* function) { callback = function; }
hook(auto (*function)(P...) -> R) { callback = function; }
template<typename C> hook(auto (C::*function)(P...) -> R, C* object) { callback = {function, object}; }
template<typename C> hook(auto (C::*function)(P...) const -> R, C* object) { callback = {function, object}; }
template<typename L> hook(const L& function) { callback = function; }
auto operator=(const hook& source) -> hook& { callback = source.callback; return *this; }
};
#if defined(DEBUGGER) #if defined(DEBUGGER)
#define privileged public #define privileged public
#else #else

View File

@ -49,7 +49,7 @@ struct Interface {
virtual auto audioSample(const double*, uint) -> void {} virtual auto audioSample(const double*, uint) -> void {}
virtual auto inputPoll(uint, uint, uint) -> int16 { return 0; } virtual auto inputPoll(uint, uint, uint) -> int16 { return 0; }
virtual auto inputRumble(uint, uint, uint, bool) -> void {} virtual auto inputRumble(uint, uint, uint, bool) -> void {}
virtual auto dipSettings(const Markup::Node&) -> uint { return 0; } virtual auto dipSettings(Markup::Node) -> uint { return 0; }
virtual auto notify(string text) -> void { print(text, "\n"); } virtual auto notify(string text) -> void { print(text, "\n"); }
}; };
Bind* bind = nullptr; Bind* bind = nullptr;
@ -62,7 +62,7 @@ struct Interface {
auto audioSample(const double* samples, uint channels) -> void { return bind->audioSample(samples, channels); } auto audioSample(const double* samples, uint channels) -> void { return bind->audioSample(samples, channels); }
auto inputPoll(uint port, uint device, uint input) -> int16 { return bind->inputPoll(port, device, input); } auto inputPoll(uint port, uint device, uint input) -> int16 { return bind->inputPoll(port, device, input); }
auto inputRumble(uint port, uint device, uint input, bool enable) -> void { return bind->inputRumble(port, device, input, enable); } auto inputRumble(uint port, uint device, uint input, bool enable) -> void { return bind->inputRumble(port, device, input, enable); }
auto dipSettings(const Markup::Node& node) -> uint { return bind->dipSettings(node); } auto dipSettings(Markup::Node node) -> uint { return bind->dipSettings(node); }
template<typename... P> auto notify(P&&... p) -> void { return bind->notify({forward<P>(p)...}); } template<typename... P> auto notify(P&&... p) -> void { return bind->notify({forward<P>(p)...}); }
//information //information

View File

@ -169,8 +169,8 @@ auto Interface::cheatSet(const lstring& list) -> void {
lstring codes = codeset.split("+"); lstring codes = codeset.split("+");
for(auto& code : codes) { for(auto& code : codes) {
lstring part = code.split("/"); lstring part = code.split("/");
if(part.size() == 2) cheat.append(hex(part[0]), hex(part[1])); if(part.size() == 2) cheat.append(part[0].hex(), part[1].hex());
if(part.size() == 3) cheat.append(hex(part[0]), hex(part[1]), hex(part[2])); if(part.size() == 3) cheat.append(part[0].hex(), part[1].hex(), part[2].hex());
} }
} }
} }

View File

@ -168,8 +168,8 @@ auto Interface::cheatSet(const lstring& list) -> void {
lstring codes = codeset.split("+"); lstring codes = codeset.split("+");
for(auto& code : codes) { for(auto& code : codes) {
lstring part = code.split("/"); lstring part = code.split("/");
if(part.size() == 2) cheat.append(hex(part[0]), hex(part[1])); if(part.size() == 2) cheat.append(part[0].hex(), part[1].hex());
if(part.size() == 3) cheat.append(hex(part[0]), hex(part[1]), hex(part[2])); if(part.size() == 3) cheat.append(part[0].hex(), part[1].hex(), part[2].hex());
} }
} }
} }

View File

@ -402,7 +402,7 @@ auto R65816::disassemble(uint24 addr, bool e, bool m, bool x) -> string {
#undef a8 #undef a8
#undef x8 #undef x8
s.append(t, " A:{0} X:{1} Y:{2} S:{3} D:{4} B:{5} ", format{ s.append(t, " A:{0} X:{1} Y:{2} S:{3} D:{4} B:{5} ", string_format{
hex(r.a.w, 4), hex(r.x.w, 4), hex(r.y.w, 4), hex(r.a.w, 4), hex(r.x.w, 4), hex(r.y.w, 4),
hex(r.s.w, 4), hex(r.d.w, 4), hex(r.db, 2) hex(r.s.w, 4), hex(r.d.w, 4), hex(r.db, 2)
}); });

View File

@ -1,5 +1,5 @@
auto R65816::op_nop() { auto R65816::op_nop() {
L ioIRQ(); L idleIRQ();
} }
auto R65816::op_wdm() { auto R65816::op_wdm() {
@ -7,11 +7,9 @@ L readPC();
} }
auto R65816::op_xba() { auto R65816::op_xba() {
io(); idle();
L io(); L idle();
r.a.l ^= r.a.h; r.a.w = r.a.w >> 8 | r.a.w << 8;
r.a.h ^= r.a.l;
r.a.l ^= r.a.h;
r.p.n = (r.a.l & 0x80); r.p.n = (r.a.l & 0x80);
r.p.z = (r.a.l == 0); r.p.z = (r.a.l == 0);
} }
@ -22,10 +20,10 @@ auto R65816::op_move_b(int adjust) {
r.db = dp; r.db = dp;
rd.l = readLong(sp << 16 | r.x.w); rd.l = readLong(sp << 16 | r.x.w);
writeLong(dp << 16 | r.y.w, rd.l); writeLong(dp << 16 | r.y.w, rd.l);
io(); idle();
r.x.l += adjust; r.x.l += adjust;
r.y.l += adjust; r.y.l += adjust;
L io(); L idle();
if(r.a.w--) r.pc.w -= 3; if(r.a.w--) r.pc.w -= 3;
} }
@ -35,10 +33,10 @@ auto R65816::op_move_w(int adjust) {
r.db = dp; r.db = dp;
rd.l = readLong(sp << 16 | r.x.w); rd.l = readLong(sp << 16 | r.x.w);
writeLong(dp << 16 | r.y.w, rd.l); writeLong(dp << 16 | r.y.w, rd.l);
io(); idle();
r.x.w += adjust; r.x.w += adjust;
r.y.w += adjust; r.y.w += adjust;
L io(); L idle();
if(r.a.w--) r.pc.w -= 3; if(r.a.w--) r.pc.w -= 3;
} }
@ -57,20 +55,20 @@ L r.pc.h = readLong(vector + 1);
auto R65816::op_stp() { auto R65816::op_stp() {
while(r.wai = true) { while(r.wai = true) {
L io(); L idle();
} }
} }
auto R65816::op_wai() { auto R65816::op_wai() {
r.wai = true; r.wai = true;
while(r.wai) { while(r.wai) {
L io(); L idle();
} }
io(); idle();
} }
auto R65816::op_xce() { auto R65816::op_xce() {
L ioIRQ(); L idleIRQ();
bool carry = r.p.c; bool carry = r.p.c;
r.p.c = r.e; r.p.c = r.e;
r.e = carry; r.e = carry;
@ -83,24 +81,19 @@ L ioIRQ();
} }
} }
//auto R65816::op_flag(bool& flag, bool value) {
//L ioIRQ();
// flag = value;
//}
auto R65816::op_set_flag(uint bit) { auto R65816::op_set_flag(uint bit) {
L ioIRQ(); L idleIRQ();
r.p |= 1 << bit; r.p |= 1 << bit;
} }
auto R65816::op_clear_flag(uint bit) { auto R65816::op_clear_flag(uint bit) {
L ioIRQ(); L idleIRQ();
r.p &= ~(1 << bit); r.p &= ~(1 << bit);
} }
auto R65816::op_pflag(bool mode) { auto R65816::op_pflag(bool mode) {
rd.l = readPC(); rd.l = readPC();
L io(); L idle();
r.p = (mode ? r.p | rd.l : r.p & ~rd.l); r.p = (mode ? r.p | rd.l : r.p & ~rd.l);
E r.p.m = 1, r.p.x = 1; E r.p.m = 1, r.p.x = 1;
if(r.p.x) { if(r.p.x) {
@ -110,89 +103,89 @@ E r.p.m = 1, r.p.x = 1;
} }
auto R65816::op_transfer_b(Reg16& from, Reg16& to) { auto R65816::op_transfer_b(Reg16& from, Reg16& to) {
L ioIRQ(); L idleIRQ();
to.l = from.l; to.l = from.l;
r.p.n = (to.l & 0x80); r.p.n = (to.l & 0x80);
r.p.z = (to.l == 0); r.p.z = (to.l == 0);
} }
auto R65816::op_transfer_w(Reg16& from, Reg16& to) { auto R65816::op_transfer_w(Reg16& from, Reg16& to) {
L ioIRQ(); L idleIRQ();
to.w = from.w; to.w = from.w;
r.p.n = (to.w & 0x8000); r.p.n = (to.w & 0x8000);
r.p.z = (to.w == 0); r.p.z = (to.w == 0);
} }
auto R65816::op_tcs() { auto R65816::op_tcs() {
L ioIRQ(); L idleIRQ();
r.s.w = r.a.w; r.s.w = r.a.w;
E r.s.h = 0x01; E r.s.h = 0x01;
} }
auto R65816::op_tsx_b() { auto R65816::op_tsx_b() {
L ioIRQ(); L idleIRQ();
r.x.l = r.s.l; r.x.l = r.s.l;
r.p.n = (r.x.l & 0x80); r.p.n = (r.x.l & 0x80);
r.p.z = (r.x.l == 0); r.p.z = (r.x.l == 0);
} }
auto R65816::op_tsx_w() { auto R65816::op_tsx_w() {
L ioIRQ(); L idleIRQ();
r.x.w = r.s.w; r.x.w = r.s.w;
r.p.n = (r.x.w & 0x8000); r.p.n = (r.x.w & 0x8000);
r.p.z = (r.x.w == 0); r.p.z = (r.x.w == 0);
} }
auto R65816::op_txs() { auto R65816::op_txs() {
L ioIRQ(); L idleIRQ();
E r.s.l = r.x.l; E r.s.l = r.x.l;
N r.s.w = r.x.w; N r.s.w = r.x.w;
} }
auto R65816::op_push_b(Reg16& reg) { auto R65816::op_push_b(Reg16& reg) {
io(); idle();
L writeSP(reg.l); L writeSP(reg.l);
} }
auto R65816::op_push_w(Reg16& reg) { auto R65816::op_push_w(Reg16& reg) {
io(); idle();
writeSP(reg.h); writeSP(reg.h);
L writeSP(reg.l); L writeSP(reg.l);
} }
auto R65816::op_phd() { auto R65816::op_phd() {
io(); idle();
writeSPn(r.d.h); writeSPn(r.d.h);
L writeSPn(r.d.l); L writeSPn(r.d.l);
E r.s.h = 0x01; E r.s.h = 0x01;
} }
auto R65816::op_phb() { auto R65816::op_phb() {
io(); idle();
L writeSP(r.db); L writeSP(r.db);
} }
auto R65816::op_phk() { auto R65816::op_phk() {
io(); idle();
L writeSP(r.pc.b); L writeSP(r.pc.b);
} }
auto R65816::op_php() { auto R65816::op_php() {
io(); idle();
L writeSP(r.p); L writeSP(r.p);
} }
auto R65816::op_pull_b(Reg16& reg) { auto R65816::op_pull_b(Reg16& reg) {
io(); idle();
io(); idle();
L reg.l = readSP(); L reg.l = readSP();
r.p.n = (reg.l & 0x80); r.p.n = (reg.l & 0x80);
r.p.z = (reg.l == 0); r.p.z = (reg.l == 0);
} }
auto R65816::op_pull_w(Reg16& reg) { auto R65816::op_pull_w(Reg16& reg) {
io(); idle();
io(); idle();
reg.l = readSP(); reg.l = readSP();
L reg.h = readSP(); L reg.h = readSP();
r.p.n = (reg.w & 0x8000); r.p.n = (reg.w & 0x8000);
@ -200,8 +193,8 @@ L reg.h = readSP();
} }
auto R65816::op_pld() { auto R65816::op_pld() {
io(); idle();
io(); idle();
r.d.l = readSPn(); r.d.l = readSPn();
L r.d.h = readSPn(); L r.d.h = readSPn();
r.p.n = (r.d.w & 0x8000); r.p.n = (r.d.w & 0x8000);
@ -210,16 +203,16 @@ E r.s.h = 0x01;
} }
auto R65816::op_plb() { auto R65816::op_plb() {
io(); idle();
io(); idle();
L r.db = readSP(); L r.db = readSP();
r.p.n = (r.db & 0x80); r.p.n = (r.db & 0x80);
r.p.z = (r.db == 0); r.p.z = (r.db == 0);
} }
auto R65816::op_plp() { auto R65816::op_plp() {
io(); idle();
io(); idle();
L r.p = readSP(); L r.p = readSP();
E r.p.m = 1, r.p.x = 1; E r.p.m = 1, r.p.x = 1;
if(r.p.x) { if(r.p.x) {
@ -238,7 +231,7 @@ E r.s.h = 0x01;
auto R65816::op_pei() { auto R65816::op_pei() {
dp = readPC(); dp = readPC();
io2(); idle2();
aa.l = readDPn(dp + 0); aa.l = readDPn(dp + 0);
aa.h = readDPn(dp + 1); aa.h = readDPn(dp + 1);
writeSPn(aa.h); writeSPn(aa.h);
@ -249,7 +242,7 @@ E r.s.h = 0x01;
auto R65816::op_per() { auto R65816::op_per() {
aa.l = readPC(); aa.l = readPC();
aa.h = readPC(); aa.h = readPC();
io(); idle();
rd.w = r.pc.d + (int16)aa.w; rd.w = r.pc.d + (int16)aa.w;
writeSPn(rd.h); writeSPn(rd.h);
L writeSPn(rd.l); L writeSPn(rd.l);

View File

@ -4,8 +4,8 @@ L rd.l = readPC();
} else { } else {
rd.l = readPC(); rd.l = readPC();
aa.w = r.pc.d + (int8)rd.l; aa.w = r.pc.d + (int8)rd.l;
io6(aa.w); idle6(aa.w);
L io(); L idle();
r.pc.w = aa.w; r.pc.w = aa.w;
} }
} }
@ -13,15 +13,15 @@ L io();
auto R65816::op_bra() { auto R65816::op_bra() {
rd.l = readPC(); rd.l = readPC();
aa.w = r.pc.d + (int8)rd.l; aa.w = r.pc.d + (int8)rd.l;
io6(aa.w); idle6(aa.w);
L io(); L idle();
r.pc.w = aa.w; r.pc.w = aa.w;
} }
auto R65816::op_brl() { auto R65816::op_brl() {
rd.l = readPC(); rd.l = readPC();
rd.h = readPC(); rd.h = readPC();
L io(); L idle();
r.pc.w = r.pc.d + (int16)rd.w; r.pc.w = r.pc.d + (int16)rd.w;
} }
@ -49,7 +49,7 @@ L rd.h = readAddr(aa.w + 1);
auto R65816::op_jmp_iaddrx() { auto R65816::op_jmp_iaddrx() {
aa.l = readPC(); aa.l = readPC();
aa.h = readPC(); aa.h = readPC();
io(); idle();
rd.l = readPB(aa.w + r.x.w + 0); rd.l = readPB(aa.w + r.x.w + 0);
L rd.h = readPB(aa.w + r.x.w + 1); L rd.h = readPB(aa.w + r.x.w + 1);
r.pc.w = rd.w; r.pc.w = rd.w;
@ -67,7 +67,7 @@ L rd.b = readAddr(aa.w + 2);
auto R65816::op_jsr_addr() { auto R65816::op_jsr_addr() {
aa.l = readPC(); aa.l = readPC();
aa.h = readPC(); aa.h = readPC();
io(); idle();
r.pc.w--; r.pc.w--;
writeSP(r.pc.h); writeSP(r.pc.h);
L writeSP(r.pc.l); L writeSP(r.pc.l);
@ -78,7 +78,7 @@ auto R65816::op_jsr_long() {
aa.l = readPC(); aa.l = readPC();
aa.h = readPC(); aa.h = readPC();
writeSPn(r.pc.b); writeSPn(r.pc.b);
io(); idle();
aa.b = readPC(); aa.b = readPC();
r.pc.w--; r.pc.w--;
writeSPn(r.pc.h); writeSPn(r.pc.h);
@ -92,7 +92,7 @@ auto R65816::op_jsr_iaddrx() {
writeSPn(r.pc.h); writeSPn(r.pc.h);
writeSPn(r.pc.l); writeSPn(r.pc.l);
aa.h = readPC(); aa.h = readPC();
io(); idle();
rd.l = readPB(aa.w + r.x.w + 0); rd.l = readPB(aa.w + r.x.w + 0);
L rd.h = readPB(aa.w + r.x.w + 1); L rd.h = readPB(aa.w + r.x.w + 1);
r.pc.w = rd.w; r.pc.w = rd.w;
@ -100,8 +100,8 @@ E r.s.h = 0x01;
} }
auto R65816::op_rti() { auto R65816::op_rti() {
io(); idle();
io(); idle();
r.p = readSP(); r.p = readSP();
E r.p.m = 1, r.p.x = 1; E r.p.m = 1, r.p.x = 1;
if(r.p.x) { if(r.p.x) {
@ -118,17 +118,17 @@ E r.p.m = 1, r.p.x = 1;
} }
auto R65816::op_rts() { auto R65816::op_rts() {
io(); idle();
io(); idle();
rd.l = readSP(); rd.l = readSP();
rd.h = readSP(); rd.h = readSP();
L io(); L idle();
r.pc.w = ++rd.w; r.pc.w = ++rd.w;
} }
auto R65816::op_rtl() { auto R65816::op_rtl() {
io(); idle();
io(); idle();
rd.l = readSPn(); rd.l = readSPn();
rd.h = readSPn(); rd.h = readSPn();
L rd.b = readSPn(); L rd.b = readSPn();

View File

@ -38,7 +38,7 @@ L rd.h = readDB(aa.w + 1);
auto R65816::op_read_addrx_b(fp op) { auto R65816::op_read_addrx_b(fp op) {
aa.l = readPC(); aa.l = readPC();
aa.h = readPC(); aa.h = readPC();
io4(aa.w, aa.w + r.x.w); idle4(aa.w, aa.w + r.x.w);
L rd.l = readDB(aa.w + r.x.w); L rd.l = readDB(aa.w + r.x.w);
call(op); call(op);
} }
@ -46,7 +46,7 @@ L rd.l = readDB(aa.w + r.x.w);
auto R65816::op_read_addrx_w(fp op) { auto R65816::op_read_addrx_w(fp op) {
aa.l = readPC(); aa.l = readPC();
aa.h = readPC(); aa.h = readPC();
io4(aa.w, aa.w + r.x.w); idle4(aa.w, aa.w + r.x.w);
rd.l = readDB(aa.w + r.x.w + 0); rd.l = readDB(aa.w + r.x.w + 0);
L rd.h = readDB(aa.w + r.x.w + 1); L rd.h = readDB(aa.w + r.x.w + 1);
call(op); call(op);
@ -55,7 +55,7 @@ L rd.h = readDB(aa.w + r.x.w + 1);
auto R65816::op_read_addry_b(fp op) { auto R65816::op_read_addry_b(fp op) {
aa.l = readPC(); aa.l = readPC();
aa.h = readPC(); aa.h = readPC();
io4(aa.w, aa.w + r.y.w); idle4(aa.w, aa.w + r.y.w);
L rd.l = readDB(aa.w + r.y.w); L rd.l = readDB(aa.w + r.y.w);
call(op); call(op);
} }
@ -63,7 +63,7 @@ L rd.l = readDB(aa.w + r.y.w);
auto R65816::op_read_addry_w(fp op) { auto R65816::op_read_addry_w(fp op) {
aa.l = readPC(); aa.l = readPC();
aa.h = readPC(); aa.h = readPC();
io4(aa.w, aa.w + r.y.w); idle4(aa.w, aa.w + r.y.w);
rd.l = readDB(aa.w + r.y.w + 0); rd.l = readDB(aa.w + r.y.w + 0);
L rd.h = readDB(aa.w + r.y.w + 1); L rd.h = readDB(aa.w + r.y.w + 1);
call(op); call(op);
@ -105,14 +105,14 @@ L rd.h = readLong(aa.d + r.x.w + 1);
auto R65816::op_read_dp_b(fp op) { auto R65816::op_read_dp_b(fp op) {
dp = readPC(); dp = readPC();
io2(); idle2();
L rd.l = readDP(dp); L rd.l = readDP(dp);
call(op); call(op);
} }
auto R65816::op_read_dp_w(fp op) { auto R65816::op_read_dp_w(fp op) {
dp = readPC(); dp = readPC();
io2(); idle2();
rd.l = readDP(dp + 0); rd.l = readDP(dp + 0);
L rd.h = readDP(dp + 1); L rd.h = readDP(dp + 1);
call(op); call(op);
@ -120,16 +120,16 @@ L rd.h = readDP(dp + 1);
auto R65816::op_read_dpr_b(fp op, Reg16& reg) { auto R65816::op_read_dpr_b(fp op, Reg16& reg) {
dp = readPC(); dp = readPC();
io2(); idle2();
io(); idle();
L rd.l = readDP(dp + reg.w); L rd.l = readDP(dp + reg.w);
call(op); call(op);
} }
auto R65816::op_read_dpr_w(fp op, Reg16& reg) { auto R65816::op_read_dpr_w(fp op, Reg16& reg) {
dp = readPC(); dp = readPC();
io2(); idle2();
io(); idle();
rd.l = readDP(dp + reg.w + 0); rd.l = readDP(dp + reg.w + 0);
L rd.h = readDP(dp + reg.w + 1); L rd.h = readDP(dp + reg.w + 1);
call(op); call(op);
@ -137,7 +137,7 @@ L rd.h = readDP(dp + reg.w + 1);
auto R65816::op_read_idp_b(fp op) { auto R65816::op_read_idp_b(fp op) {
dp = readPC(); dp = readPC();
io2(); idle2();
aa.l = readDP(dp + 0); aa.l = readDP(dp + 0);
aa.h = readDP(dp + 1); aa.h = readDP(dp + 1);
L rd.l = readDB(aa.w); L rd.l = readDB(aa.w);
@ -146,7 +146,7 @@ L rd.l = readDB(aa.w);
auto R65816::op_read_idp_w(fp op) { auto R65816::op_read_idp_w(fp op) {
dp = readPC(); dp = readPC();
io2(); idle2();
aa.l = readDP(dp + 0); aa.l = readDP(dp + 0);
aa.h = readDP(dp + 1); aa.h = readDP(dp + 1);
rd.l = readDB(aa.w + 0); rd.l = readDB(aa.w + 0);
@ -156,8 +156,8 @@ L rd.h = readDB(aa.w + 1);
auto R65816::op_read_idpx_b(fp op) { auto R65816::op_read_idpx_b(fp op) {
dp = readPC(); dp = readPC();
io2(); idle2();
io(); idle();
aa.l = readDP(dp + r.x.w + 0); aa.l = readDP(dp + r.x.w + 0);
aa.h = readDP(dp + r.x.w + 1); aa.h = readDP(dp + r.x.w + 1);
L rd.l = readDB(aa.w); L rd.l = readDB(aa.w);
@ -166,8 +166,8 @@ L rd.l = readDB(aa.w);
auto R65816::op_read_idpx_w(fp op) { auto R65816::op_read_idpx_w(fp op) {
dp = readPC(); dp = readPC();
io2(); idle2();
io(); idle();
aa.l = readDP(dp + r.x.w + 0); aa.l = readDP(dp + r.x.w + 0);
aa.h = readDP(dp + r.x.w + 1); aa.h = readDP(dp + r.x.w + 1);
rd.l = readDB(aa.w + 0); rd.l = readDB(aa.w + 0);
@ -177,20 +177,20 @@ L rd.h = readDB(aa.w + 1);
auto R65816::op_read_idpy_b(fp op) { auto R65816::op_read_idpy_b(fp op) {
dp = readPC(); dp = readPC();
io2(); idle2();
aa.l = readDP(dp + 0); aa.l = readDP(dp + 0);
aa.h = readDP(dp + 1); aa.h = readDP(dp + 1);
io4(aa.w, aa.w + r.y.w); idle4(aa.w, aa.w + r.y.w);
L rd.l = readDB(aa.w + r.y.w); L rd.l = readDB(aa.w + r.y.w);
call(op); call(op);
} }
auto R65816::op_read_idpy_w(fp op) { auto R65816::op_read_idpy_w(fp op) {
dp = readPC(); dp = readPC();
io2(); idle2();
aa.l = readDP(dp + 0); aa.l = readDP(dp + 0);
aa.h = readDP(dp + 1); aa.h = readDP(dp + 1);
io4(aa.w, aa.w + r.y.w); idle4(aa.w, aa.w + r.y.w);
rd.l = readDB(aa.w + r.y.w + 0); rd.l = readDB(aa.w + r.y.w + 0);
L rd.h = readDB(aa.w + r.y.w + 1); L rd.h = readDB(aa.w + r.y.w + 1);
call(op); call(op);
@ -198,7 +198,7 @@ L rd.h = readDB(aa.w + r.y.w + 1);
auto R65816::op_read_ildp_b(fp op) { auto R65816::op_read_ildp_b(fp op) {
dp = readPC(); dp = readPC();
io2(); idle2();
aa.l = readDPn(dp + 0); aa.l = readDPn(dp + 0);
aa.h = readDPn(dp + 1); aa.h = readDPn(dp + 1);
aa.b = readDPn(dp + 2); aa.b = readDPn(dp + 2);
@ -208,7 +208,7 @@ L rd.l = readLong(aa.d);
auto R65816::op_read_ildp_w(fp op) { auto R65816::op_read_ildp_w(fp op) {
dp = readPC(); dp = readPC();
io2(); idle2();
aa.l = readDPn(dp + 0); aa.l = readDPn(dp + 0);
aa.h = readDPn(dp + 1); aa.h = readDPn(dp + 1);
aa.b = readDPn(dp + 2); aa.b = readDPn(dp + 2);
@ -219,7 +219,7 @@ L rd.h = readLong(aa.d + 1);
auto R65816::op_read_ildpy_b(fp op) { auto R65816::op_read_ildpy_b(fp op) {
dp = readPC(); dp = readPC();
io2(); idle2();
aa.l = readDPn(dp + 0); aa.l = readDPn(dp + 0);
aa.h = readDPn(dp + 1); aa.h = readDPn(dp + 1);
aa.b = readDPn(dp + 2); aa.b = readDPn(dp + 2);
@ -229,7 +229,7 @@ L rd.l = readLong(aa.d + r.y.w);
auto R65816::op_read_ildpy_w(fp op) { auto R65816::op_read_ildpy_w(fp op) {
dp = readPC(); dp = readPC();
io2(); idle2();
aa.l = readDPn(dp + 0); aa.l = readDPn(dp + 0);
aa.h = readDPn(dp + 1); aa.h = readDPn(dp + 1);
aa.b = readDPn(dp + 2); aa.b = readDPn(dp + 2);
@ -240,14 +240,14 @@ L rd.h = readLong(aa.d + r.y.w + 1);
auto R65816::op_read_sr_b(fp op) { auto R65816::op_read_sr_b(fp op) {
sp = readPC(); sp = readPC();
io(); idle();
L rd.l = readSP(sp); L rd.l = readSP(sp);
call(op); call(op);
} }
auto R65816::op_read_sr_w(fp op) { auto R65816::op_read_sr_w(fp op) {
sp = readPC(); sp = readPC();
io(); idle();
rd.l = readSP(sp + 0); rd.l = readSP(sp + 0);
L rd.h = readSP(sp + 1); L rd.h = readSP(sp + 1);
call(op); call(op);
@ -255,20 +255,20 @@ L rd.h = readSP(sp + 1);
auto R65816::op_read_isry_b(fp op) { auto R65816::op_read_isry_b(fp op) {
sp = readPC(); sp = readPC();
io(); idle();
aa.l = readSP(sp + 0); aa.l = readSP(sp + 0);
aa.h = readSP(sp + 1); aa.h = readSP(sp + 1);
io(); idle();
L rd.l = readDB(aa.w + r.y.w); L rd.l = readDB(aa.w + r.y.w);
call(op); call(op);
} }
auto R65816::op_read_isry_w(fp op) { auto R65816::op_read_isry_w(fp op) {
sp = readPC(); sp = readPC();
io(); idle();
aa.l = readSP(sp + 0); aa.l = readSP(sp + 0);
aa.h = readSP(sp + 1); aa.h = readSP(sp + 1);
io(); idle();
rd.l = readDB(aa.w + r.y.w + 0); rd.l = readDB(aa.w + r.y.w + 0);
L rd.h = readDB(aa.w + r.y.w + 1); L rd.h = readDB(aa.w + r.y.w + 1);
call(op); call(op);

View File

@ -1,19 +1,19 @@
auto R65816::op_adjust_imm_b(Reg16& reg, int adjust) { auto R65816::op_adjust_imm_b(Reg16& reg, int adjust) {
L ioIRQ(); L idleIRQ();
reg.l += adjust; reg.l += adjust;
r.p.n = (reg.l & 0x80); r.p.n = (reg.l & 0x80);
r.p.z = (reg.l == 0); r.p.z = (reg.l == 0);
} }
auto R65816::op_adjust_imm_w(Reg16& reg, int adjust) { auto R65816::op_adjust_imm_w(Reg16& reg, int adjust) {
L ioIRQ(); L idleIRQ();
reg.w += adjust; reg.w += adjust;
r.p.n = (reg.w & 0x8000); r.p.n = (reg.w & 0x8000);
r.p.z = (reg.w == 0); r.p.z = (reg.w == 0);
} }
auto R65816::op_asl_imm_b() { auto R65816::op_asl_imm_b() {
L ioIRQ(); L idleIRQ();
r.p.c = (r.a.l & 0x80); r.p.c = (r.a.l & 0x80);
r.a.l <<= 1; r.a.l <<= 1;
r.p.n = (r.a.l & 0x80); r.p.n = (r.a.l & 0x80);
@ -21,7 +21,7 @@ L ioIRQ();
} }
auto R65816::op_asl_imm_w() { auto R65816::op_asl_imm_w() {
L ioIRQ(); L idleIRQ();
r.p.c = (r.a.w & 0x8000); r.p.c = (r.a.w & 0x8000);
r.a.w <<= 1; r.a.w <<= 1;
r.p.n = (r.a.w & 0x8000); r.p.n = (r.a.w & 0x8000);
@ -29,7 +29,7 @@ L ioIRQ();
} }
auto R65816::op_lsr_imm_b() { auto R65816::op_lsr_imm_b() {
L ioIRQ(); L idleIRQ();
r.p.c = (r.a.l & 0x01); r.p.c = (r.a.l & 0x01);
r.a.l >>= 1; r.a.l >>= 1;
r.p.n = (r.a.l & 0x80); r.p.n = (r.a.l & 0x80);
@ -37,7 +37,7 @@ L ioIRQ();
} }
auto R65816::op_lsr_imm_w() { auto R65816::op_lsr_imm_w() {
L ioIRQ(); L idleIRQ();
r.p.c = (r.a.w & 0x0001); r.p.c = (r.a.w & 0x0001);
r.a.w >>= 1; r.a.w >>= 1;
r.p.n = (r.a.w & 0x8000); r.p.n = (r.a.w & 0x8000);
@ -45,7 +45,7 @@ L ioIRQ();
} }
auto R65816::op_rol_imm_b() { auto R65816::op_rol_imm_b() {
L ioIRQ(); L idleIRQ();
bool carry = r.p.c; bool carry = r.p.c;
r.p.c = (r.a.l & 0x80); r.p.c = (r.a.l & 0x80);
r.a.l = (r.a.l << 1) | carry; r.a.l = (r.a.l << 1) | carry;
@ -54,7 +54,7 @@ L ioIRQ();
} }
auto R65816::op_rol_imm_w() { auto R65816::op_rol_imm_w() {
L ioIRQ(); L idleIRQ();
bool carry = r.p.c; bool carry = r.p.c;
r.p.c = (r.a.w & 0x8000); r.p.c = (r.a.w & 0x8000);
r.a.w = (r.a.w << 1) | carry; r.a.w = (r.a.w << 1) | carry;
@ -63,7 +63,7 @@ L ioIRQ();
} }
auto R65816::op_ror_imm_b() { auto R65816::op_ror_imm_b() {
L ioIRQ(); L idleIRQ();
bool carry = r.p.c; bool carry = r.p.c;
r.p.c = (r.a.l & 0x01); r.p.c = (r.a.l & 0x01);
r.a.l = (carry << 7) | (r.a.l >> 1); r.a.l = (carry << 7) | (r.a.l >> 1);
@ -72,7 +72,7 @@ L ioIRQ();
} }
auto R65816::op_ror_imm_w() { auto R65816::op_ror_imm_w() {
L ioIRQ(); L idleIRQ();
bool carry = r.p.c; bool carry = r.p.c;
r.p.c = (r.a.w & 0x0001); r.p.c = (r.a.w & 0x0001);
r.a.w = (carry << 15) | (r.a.w >> 1); r.a.w = (carry << 15) | (r.a.w >> 1);
@ -84,7 +84,7 @@ auto R65816::op_adjust_addr_b(fp op) {
aa.l = readPC(); aa.l = readPC();
aa.h = readPC(); aa.h = readPC();
rd.l = readDB(aa.w); rd.l = readDB(aa.w);
io(); idle();
call(op); call(op);
L writeDB(aa.w, rd.l); L writeDB(aa.w, rd.l);
} }
@ -94,7 +94,7 @@ auto R65816::op_adjust_addr_w(fp op) {
aa.h = readPC(); aa.h = readPC();
rd.l = readDB(aa.w + 0); rd.l = readDB(aa.w + 0);
rd.h = readDB(aa.w + 1); rd.h = readDB(aa.w + 1);
io(); idle();
call(op); call(op);
writeDB(aa.w + 1, rd.h); writeDB(aa.w + 1, rd.h);
L writeDB(aa.w + 0, rd.l); L writeDB(aa.w + 0, rd.l);
@ -103,9 +103,9 @@ L writeDB(aa.w + 0, rd.l);
auto R65816::op_adjust_addrx_b(fp op) { auto R65816::op_adjust_addrx_b(fp op) {
aa.l = readPC(); aa.l = readPC();
aa.h = readPC(); aa.h = readPC();
io(); idle();
rd.l = readDB(aa.w + r.x.w); rd.l = readDB(aa.w + r.x.w);
io(); idle();
call(op); call(op);
L writeDB(aa.w + r.x.w, rd.l); L writeDB(aa.w + r.x.w, rd.l);
} }
@ -113,10 +113,10 @@ L writeDB(aa.w + r.x.w, rd.l);
auto R65816::op_adjust_addrx_w(fp op) { auto R65816::op_adjust_addrx_w(fp op) {
aa.l = readPC(); aa.l = readPC();
aa.h = readPC(); aa.h = readPC();
io(); idle();
rd.l = readDB(aa.w + r.x.w + 0); rd.l = readDB(aa.w + r.x.w + 0);
rd.h = readDB(aa.w + r.x.w + 1); rd.h = readDB(aa.w + r.x.w + 1);
io(); idle();
call(op); call(op);
writeDB(aa.w + r.x.w + 1, rd.h); writeDB(aa.w + r.x.w + 1, rd.h);
L writeDB(aa.w + r.x.w + 0, rd.l); L writeDB(aa.w + r.x.w + 0, rd.l);
@ -124,19 +124,19 @@ L writeDB(aa.w + r.x.w + 0, rd.l);
auto R65816::op_adjust_dp_b(fp op) { auto R65816::op_adjust_dp_b(fp op) {
dp = readPC(); dp = readPC();
io2(); idle2();
rd.l = readDP(dp); rd.l = readDP(dp);
io(); idle();
call(op); call(op);
L writeDP(dp, rd.l); L writeDP(dp, rd.l);
} }
auto R65816::op_adjust_dp_w(fp op) { auto R65816::op_adjust_dp_w(fp op) {
dp = readPC(); dp = readPC();
io2(); idle2();
rd.l = readDP(dp + 0); rd.l = readDP(dp + 0);
rd.h = readDP(dp + 1); rd.h = readDP(dp + 1);
io(); idle();
call(op); call(op);
writeDP(dp + 1, rd.h); writeDP(dp + 1, rd.h);
L writeDP(dp + 0, rd.l); L writeDP(dp + 0, rd.l);
@ -144,21 +144,21 @@ L writeDP(dp + 0, rd.l);
auto R65816::op_adjust_dpx_b(fp op) { auto R65816::op_adjust_dpx_b(fp op) {
dp = readPC(); dp = readPC();
io2(); idle2();
io(); idle();
rd.l = readDP(dp + r.x.w); rd.l = readDP(dp + r.x.w);
io(); idle();
call(op); call(op);
L writeDP(dp + r.x.w, rd.l); L writeDP(dp + r.x.w, rd.l);
} }
auto R65816::op_adjust_dpx_w(fp op) { auto R65816::op_adjust_dpx_w(fp op) {
dp = readPC(); dp = readPC();
io2(); idle2();
io(); idle();
rd.l = readDP(dp + r.x.w + 0); rd.l = readDP(dp + r.x.w + 0);
rd.h = readDP(dp + r.x.w + 1); rd.h = readDP(dp + r.x.w + 1);
io(); idle();
call(op); call(op);
writeDP(dp + r.x.w + 1, rd.h); writeDP(dp + r.x.w + 1, rd.h);
L writeDP(dp + r.x.w + 0, rd.l); L writeDP(dp + r.x.w + 0, rd.l);

View File

@ -14,14 +14,14 @@ L writeDB(aa.w + 1, reg >> 8);
auto R65816::op_write_addrr_b(Reg16& reg, Reg16& idx) { auto R65816::op_write_addrr_b(Reg16& reg, Reg16& idx) {
aa.l = readPC(); aa.l = readPC();
aa.h = readPC(); aa.h = readPC();
io(); idle();
L writeDB(aa.w + idx, reg); L writeDB(aa.w + idx, reg);
} }
auto R65816::op_write_addrr_w(Reg16& reg, Reg16& idx) { auto R65816::op_write_addrr_w(Reg16& reg, Reg16& idx) {
aa.l = readPC(); aa.l = readPC();
aa.h = readPC(); aa.h = readPC();
io(); idle();
writeDB(aa.w + idx + 0, reg >> 0); writeDB(aa.w + idx + 0, reg >> 0);
L writeDB(aa.w + idx + 1, reg >> 8); L writeDB(aa.w + idx + 1, reg >> 8);
} }
@ -43,35 +43,35 @@ L writeLong(aa.d + idx + 1, r.a.h);
auto R65816::op_write_dp_b(Reg16& reg) { auto R65816::op_write_dp_b(Reg16& reg) {
dp = readPC(); dp = readPC();
io2(); idle2();
L writeDP(dp, reg); L writeDP(dp, reg);
} }
auto R65816::op_write_dp_w(Reg16& reg) { auto R65816::op_write_dp_w(Reg16& reg) {
dp = readPC(); dp = readPC();
io2(); idle2();
writeDP(dp + 0, reg >> 0); writeDP(dp + 0, reg >> 0);
L writeDP(dp + 1, reg >> 8); L writeDP(dp + 1, reg >> 8);
} }
auto R65816::op_write_dpr_b(Reg16& reg, Reg16& idx) { auto R65816::op_write_dpr_b(Reg16& reg, Reg16& idx) {
dp = readPC(); dp = readPC();
io2(); idle2();
io(); idle();
L writeDP(dp + idx, reg); L writeDP(dp + idx, reg);
} }
auto R65816::op_write_dpr_w(Reg16& reg, Reg16& idx) { auto R65816::op_write_dpr_w(Reg16& reg, Reg16& idx) {
dp = readPC(); dp = readPC();
io2(); idle2();
io(); idle();
writeDP(dp + idx + 0, reg >> 0); writeDP(dp + idx + 0, reg >> 0);
L writeDP(dp + idx + 1, reg >> 8); L writeDP(dp + idx + 1, reg >> 8);
} }
auto R65816::op_sta_idp_b() { auto R65816::op_sta_idp_b() {
dp = readPC(); dp = readPC();
io2(); idle2();
aa.l = readDP(dp + 0); aa.l = readDP(dp + 0);
aa.h = readDP(dp + 1); aa.h = readDP(dp + 1);
L writeDB(aa.w, r.a.l); L writeDB(aa.w, r.a.l);
@ -79,7 +79,7 @@ L writeDB(aa.w, r.a.l);
auto R65816::op_sta_idp_w() { auto R65816::op_sta_idp_w() {
dp = readPC(); dp = readPC();
io2(); idle2();
aa.l = readDP(dp + 0); aa.l = readDP(dp + 0);
aa.h = readDP(dp + 1); aa.h = readDP(dp + 1);
writeDB(aa.w + 0, r.a.l); writeDB(aa.w + 0, r.a.l);
@ -88,7 +88,7 @@ L writeDB(aa.w + 1, r.a.h);
auto R65816::op_sta_ildp_b() { auto R65816::op_sta_ildp_b() {
dp = readPC(); dp = readPC();
io2(); idle2();
aa.l = readDPn(dp + 0); aa.l = readDPn(dp + 0);
aa.h = readDPn(dp + 1); aa.h = readDPn(dp + 1);
aa.b = readDPn(dp + 2); aa.b = readDPn(dp + 2);
@ -97,7 +97,7 @@ L writeLong(aa.d, r.a.l);
auto R65816::op_sta_ildp_w() { auto R65816::op_sta_ildp_w() {
dp = readPC(); dp = readPC();
io2(); idle2();
aa.l = readDPn(dp + 0); aa.l = readDPn(dp + 0);
aa.h = readDPn(dp + 1); aa.h = readDPn(dp + 1);
aa.b = readDPn(dp + 2); aa.b = readDPn(dp + 2);
@ -107,8 +107,8 @@ L writeLong(aa.d + 1, r.a.h);
auto R65816::op_sta_idpx_b() { auto R65816::op_sta_idpx_b() {
dp = readPC(); dp = readPC();
io2(); idle2();
io(); idle();
aa.l = readDP(dp + r.x.w + 0); aa.l = readDP(dp + r.x.w + 0);
aa.h = readDP(dp + r.x.w + 1); aa.h = readDP(dp + r.x.w + 1);
L writeDB(aa.w, r.a.l); L writeDB(aa.w, r.a.l);
@ -116,8 +116,8 @@ L writeDB(aa.w, r.a.l);
auto R65816::op_sta_idpx_w() { auto R65816::op_sta_idpx_w() {
dp = readPC(); dp = readPC();
io2(); idle2();
io(); idle();
aa.l = readDP(dp + r.x.w + 0); aa.l = readDP(dp + r.x.w + 0);
aa.h = readDP(dp + r.x.w + 1); aa.h = readDP(dp + r.x.w + 1);
writeDB(aa.w + 0, r.a.l); writeDB(aa.w + 0, r.a.l);
@ -126,26 +126,26 @@ L writeDB(aa.w + 1, r.a.h);
auto R65816::op_sta_idpy_b() { auto R65816::op_sta_idpy_b() {
dp = readPC(); dp = readPC();
io2(); idle2();
aa.l = readDP(dp + 0); aa.l = readDP(dp + 0);
aa.h = readDP(dp + 1); aa.h = readDP(dp + 1);
io(); idle();
L writeDB(aa.w + r.y.w, r.a.l); L writeDB(aa.w + r.y.w, r.a.l);
} }
auto R65816::op_sta_idpy_w() { auto R65816::op_sta_idpy_w() {
dp = readPC(); dp = readPC();
io2(); idle2();
aa.l = readDP(dp + 0); aa.l = readDP(dp + 0);
aa.h = readDP(dp + 1); aa.h = readDP(dp + 1);
io(); idle();
writeDB(aa.w + r.y.w + 0, r.a.l); writeDB(aa.w + r.y.w + 0, r.a.l);
L writeDB(aa.w + r.y.w + 1, r.a.h); L writeDB(aa.w + r.y.w + 1, r.a.h);
} }
auto R65816::op_sta_ildpy_b() { auto R65816::op_sta_ildpy_b() {
dp = readPC(); dp = readPC();
io2(); idle2();
aa.l = readDPn(dp + 0); aa.l = readDPn(dp + 0);
aa.h = readDPn(dp + 1); aa.h = readDPn(dp + 1);
aa.b = readDPn(dp + 2); aa.b = readDPn(dp + 2);
@ -154,7 +154,7 @@ L writeLong(aa.d + r.y.w, r.a.l);
auto R65816::op_sta_ildpy_w() { auto R65816::op_sta_ildpy_w() {
dp = readPC(); dp = readPC();
io2(); idle2();
aa.l = readDPn(dp + 0); aa.l = readDPn(dp + 0);
aa.h = readDPn(dp + 1); aa.h = readDPn(dp + 1);
aa.b = readDPn(dp + 2); aa.b = readDPn(dp + 2);
@ -164,32 +164,32 @@ L writeLong(aa.d + r.y.w + 1, r.a.h);
auto R65816::op_sta_sr_b() { auto R65816::op_sta_sr_b() {
sp = readPC(); sp = readPC();
io(); idle();
L writeSP(sp, r.a.l); L writeSP(sp, r.a.l);
} }
auto R65816::op_sta_sr_w() { auto R65816::op_sta_sr_w() {
sp = readPC(); sp = readPC();
io(); idle();
writeSP(sp + 0, r.a.l); writeSP(sp + 0, r.a.l);
L writeSP(sp + 1, r.a.h); L writeSP(sp + 1, r.a.h);
} }
auto R65816::op_sta_isry_b() { auto R65816::op_sta_isry_b() {
sp = readPC(); sp = readPC();
io(); idle();
aa.l = readSP(sp + 0); aa.l = readSP(sp + 0);
aa.h = readSP(sp + 1); aa.h = readSP(sp + 1);
io(); idle();
L writeDB(aa.w + r.y.w, r.a.l); L writeDB(aa.w + r.y.w, r.a.l);
} }
auto R65816::op_sta_isry_w() { auto R65816::op_sta_isry_w() {
sp = readPC(); sp = readPC();
io(); idle();
aa.l = readSP(sp + 0); aa.l = readSP(sp + 0);
aa.h = readSP(sp + 1); aa.h = readSP(sp + 1);
io(); idle();
writeDB(aa.w + r.y.w + 0, r.a.l); writeDB(aa.w + r.y.w + 0, r.a.l);
L writeDB(aa.w + r.y.w + 1, r.a.h); L writeDB(aa.w + r.y.w + 1, r.a.h);
} }

View File

@ -19,7 +19,7 @@ namespace Processor {
#include "instructions-misc.cpp" #include "instructions-misc.cpp"
#include "switch.cpp" #include "switch.cpp"
//immediate, 2-cycle opcodes with I/O cycle will become bus read //immediate, 2-cycle opcodes with idle cycle will become bus read
//when an IRQ is to be triggered immediately after opcode completion. //when an IRQ is to be triggered immediately after opcode completion.
//this affects the following opcodes: //this affects the following opcodes:
// clc, cld, cli, clv, sec, sed, sei, // clc, cld, cli, clv, sec, sed, sei,
@ -27,36 +27,36 @@ namespace Processor {
// tcd, tcs, tdc, tsc, tsx, txs, // tcd, tcs, tdc, tsc, tsx, txs,
// inc, inx, iny, dec, dex, dey, // inc, inx, iny, dec, dex, dey,
// asl, lsr, rol, ror, nop, xce. // asl, lsr, rol, ror, nop, xce.
auto R65816::ioIRQ() -> void { auto R65816::idleIRQ() -> void {
if(interruptPending()) { if(interruptPending()) {
//modify I/O cycle to bus read cycle, do not increment PC //modify I/O cycle to bus read cycle, do not increment PC
read(r.pc.d); read(r.pc.d);
} else { } else {
io(); idle();
} }
} }
auto R65816::io2() -> void { auto R65816::idle2() -> void {
if(r.d.l != 0x00) { if(r.d.l != 0x00) {
io(); idle();
} }
} }
auto R65816::io4(uint16 x, uint16 y) -> void { auto R65816::idle4(uint16 x, uint16 y) -> void {
if(!r.p.x || (x & 0xff00) != (y & 0xff00)) { if(!r.p.x || (x & 0xff00) != (y & 0xff00)) {
io(); idle();
} }
} }
auto R65816::io6(uint16 addr) -> void { auto R65816::idle6(uint16 addr) -> void {
if(r.e && (r.pc.w & 0xff00) != (addr & 0xff00)) { if(r.e && (r.pc.w & 0xff00) != (addr & 0xff00)) {
io(); idle();
} }
} }
auto R65816::interrupt() -> void { auto R65816::interrupt() -> void {
read(r.pc.d); read(r.pc.d);
io(); idle();
N writeSP(r.pc.b); N writeSP(r.pc.b);
writeSP(r.pc.h); writeSP(r.pc.h);
writeSP(r.pc.l); writeSP(r.pc.l);

View File

@ -13,20 +13,20 @@ struct R65816 {
using fp = auto (R65816::*)() -> void; using fp = auto (R65816::*)() -> void;
virtual auto io() -> void = 0; virtual auto idle() -> void = 0;
virtual auto read(uint24 addr) -> uint8 = 0; virtual auto read(uint24 addr) -> uint8 = 0;
virtual auto write(uint24 addr, uint8 data) -> void = 0; virtual auto write(uint24 addr, uint8 data) -> void = 0;
virtual auto lastCycle() -> void = 0; virtual auto lastCycle() -> void = 0;
virtual auto interruptPending() const -> bool = 0; virtual auto interruptPending() const -> bool = 0;
virtual auto interrupt() -> void;
virtual auto readDisassembler(uint24 addr) -> uint8 { return 0; } virtual auto readDisassembler(uint24 addr) -> uint8 { return 0; }
//r65816.cpp //r65816.cpp
alwaysinline auto ioIRQ() -> void; alwaysinline auto idleIRQ() -> void;
alwaysinline auto io2() -> void; alwaysinline auto idle2() -> void;
alwaysinline auto io4(uint16 x, uint16 y) -> void; alwaysinline auto idle4(uint16 x, uint16 y) -> void;
alwaysinline auto io6(uint16 addr) -> void; alwaysinline auto idle6(uint16 addr) -> void;
auto interrupt() -> void;
//algorithms.cpp //algorithms.cpp
auto op_adc_b(); auto op_adc_b();

View File

@ -1,7 +1,7 @@
#define call (this->*op) #define call (this->*op)
auto SPC700::op_adjust(fps op, reg r) { auto SPC700::op_adjust(fps op, reg r) {
io(); idle();
r = call(r); r = call(r);
} }
@ -32,7 +32,7 @@ auto SPC700::op_adjust_dpw(int n) {
auto SPC700::op_adjust_dpx(fps op) { auto SPC700::op_adjust_dpx(fps op) {
dp = readPC(); dp = readPC();
io(); idle();
rd = readDP(dp + regs.x); rd = readDP(dp + regs.x);
rd = call(rd); rd = call(rd);
writeDP(dp + regs.x, rd); writeDP(dp + regs.x, rd);
@ -41,8 +41,8 @@ auto SPC700::op_adjust_dpx(fps op) {
auto SPC700::op_branch(bool condition) { auto SPC700::op_branch(bool condition) {
rd = readPC(); rd = readPC();
if(!condition) return; if(!condition) return;
io(); idle();
io(); idle();
regs.pc += (int8)rd; regs.pc += (int8)rd;
} }
@ -50,22 +50,22 @@ auto SPC700::op_branch_bit() {
dp = readPC(); dp = readPC();
sp = readDP(dp); sp = readDP(dp);
rd = readPC(); rd = readPC();
io(); idle();
if((bool)(sp & (1 << (opcode >> 5))) == (bool)(opcode & 0x10)) return; if((bool)(sp & (1 << (opcode >> 5))) == (bool)(opcode & 0x10)) return;
io(); idle();
io(); idle();
regs.pc += (int8)rd; regs.pc += (int8)rd;
} }
auto SPC700::op_pull(reg r) { auto SPC700::op_pull(reg r) {
io(); idle();
io(); idle();
r = readSP(); r = readSP();
} }
auto SPC700::op_push(uint8 r) { auto SPC700::op_push(uint8 r) {
io(); idle();
io(); idle();
writeSP(r); writeSP(r);
} }
@ -79,7 +79,7 @@ auto SPC700::op_read_addr(fpb op, reg r) {
auto SPC700::op_read_addri(fpb op, reg r) { auto SPC700::op_read_addri(fpb op, reg r) {
dp.l = readPC(); dp.l = readPC();
dp.h = readPC(); dp.h = readPC();
io(); idle();
rd = read(dp + r); rd = read(dp + r);
regs.a = call(regs.a, rd); regs.a = call(regs.a, rd);
} }
@ -97,7 +97,7 @@ auto SPC700::op_read_dp(fpb op, reg r) {
auto SPC700::op_read_dpi(fpb op, reg r, reg i) { auto SPC700::op_read_dpi(fpb op, reg r, reg i) {
dp = readPC(); dp = readPC();
io(); idle();
rd = readDP(dp + i); rd = readDP(dp + i);
r = call(r, rd); r = call(r, rd);
} }
@ -105,14 +105,14 @@ auto SPC700::op_read_dpi(fpb op, reg r, reg i) {
auto SPC700::op_read_dpw(fpw op) { auto SPC700::op_read_dpw(fpw op) {
dp = readPC(); dp = readPC();
rd.l = readDP(dp++); rd.l = readDP(dp++);
if(op != &SPC700::op_cpw) io(); if(op != &SPC700::op_cpw) idle();
rd.h = readDP(dp++); rd.h = readDP(dp++);
regs.ya = call(regs.ya, rd); regs.ya = call(regs.ya, rd);
} }
auto SPC700::op_read_idpx(fpb op) { auto SPC700::op_read_idpx(fpb op) {
dp = readPC() + regs.x; dp = readPC() + regs.x;
io(); idle();
sp.l = readDP(dp++); sp.l = readDP(dp++);
sp.h = readDP(dp++); sp.h = readDP(dp++);
rd = read(sp); rd = read(sp);
@ -121,7 +121,7 @@ auto SPC700::op_read_idpx(fpb op) {
auto SPC700::op_read_idpy(fpb op) { auto SPC700::op_read_idpy(fpb op) {
dp = readPC(); dp = readPC();
io(); idle();
sp.l = readDP(dp++); sp.l = readDP(dp++);
sp.h = readDP(dp++); sp.h = readDP(dp++);
rd = read(sp + regs.y); rd = read(sp + regs.y);
@ -129,7 +129,7 @@ auto SPC700::op_read_idpy(fpb op) {
} }
auto SPC700::op_read_ix(fpb op) { auto SPC700::op_read_ix(fpb op) {
io(); idle();
rd = readDP(regs.x); rd = readDP(regs.x);
regs.a = call(regs.a, rd); regs.a = call(regs.a, rd);
} }
@ -143,7 +143,7 @@ auto SPC700::op_set_addr_bit() {
switch(opcode >> 5) { switch(opcode >> 5) {
case 0: //orc addr:bit case 0: //orc addr:bit
case 1: //orc !addr:bit case 1: //orc !addr:bit
io(); idle();
regs.p.c |= (rd & (1 << bit)) ^ (bool)(opcode & 0x20); regs.p.c |= (rd & (1 << bit)) ^ (bool)(opcode & 0x20);
break; break;
case 2: //and addr:bit case 2: //and addr:bit
@ -151,14 +151,14 @@ auto SPC700::op_set_addr_bit() {
regs.p.c &= (rd & (1 << bit)) ^ (bool)(opcode & 0x20); regs.p.c &= (rd & (1 << bit)) ^ (bool)(opcode & 0x20);
break; break;
case 4: //eor addr:bit case 4: //eor addr:bit
io(); idle();
regs.p.c ^= (bool)(rd & (1 << bit)); regs.p.c ^= (bool)(rd & (1 << bit));
break; break;
case 5: //ldc addr:bit case 5: //ldc addr:bit
regs.p.c = (rd & (1 << bit)); regs.p.c = (rd & (1 << bit));
break; break;
case 6: //stc addr:bit case 6: //stc addr:bit
io(); idle();
rd = (rd & ~(1 << bit)) | (regs.p.c << bit); rd = (rd & ~(1 << bit)) | (regs.p.c << bit);
write(dp, rd); write(dp, rd);
break; break;
@ -176,8 +176,8 @@ auto SPC700::op_set_bit() {
} }
auto SPC700::op_set_flag(uint bit, bool value) { auto SPC700::op_set_flag(uint bit, bool value) {
io(); idle();
if(bit == regs.p.i.bit) io(); if(bit == regs.p.i.bit) idle();
regs.p = value ? (regs.p | (1 << bit)) : (regs.p & ~(1 << bit)); regs.p = value ? (regs.p | (1 << bit)) : (regs.p & ~(1 << bit));
} }
@ -192,7 +192,7 @@ auto SPC700::op_test_addr(bool set) {
} }
auto SPC700::op_transfer(reg from, reg to) { auto SPC700::op_transfer(reg from, reg to) {
io(); idle();
to = from; to = from;
if(&to == &regs.s) return; if(&to == &regs.s) return;
regs.p.n = (to & 0x80); regs.p.n = (to & 0x80);
@ -209,7 +209,7 @@ auto SPC700::op_write_addr(reg r) {
auto SPC700::op_write_addri(reg i) { auto SPC700::op_write_addri(reg i) {
dp.l = readPC(); dp.l = readPC();
dp.h = readPC(); dp.h = readPC();
io(); idle();
dp += i; dp += i;
read(dp); read(dp);
write(dp, regs.a); write(dp, regs.a);
@ -223,7 +223,7 @@ auto SPC700::op_write_dp(reg r) {
auto SPC700::op_write_dpi(reg r, reg i) { auto SPC700::op_write_dpi(reg r, reg i) {
dp = readPC() + i; dp = readPC() + i;
io(); idle();
readDP(dp); readDP(dp);
writeDP(dp, r); writeDP(dp, r);
} }
@ -233,7 +233,7 @@ auto SPC700::op_write_dp_const(fpb op) {
dp = readPC(); dp = readPC();
wr = readDP(dp); wr = readDP(dp);
wr = call(wr, rd); wr = call(wr, rd);
op != &SPC700::op_cmp ? writeDP(dp, wr) : io(); op != &SPC700::op_cmp ? writeDP(dp, wr) : idle();
} }
auto SPC700::op_write_dp_dp(fpb op) { auto SPC700::op_write_dp_dp(fpb op) {
@ -242,15 +242,15 @@ auto SPC700::op_write_dp_dp(fpb op) {
dp = readPC(); dp = readPC();
if(op != &SPC700::op_st) wr = readDP(dp); if(op != &SPC700::op_st) wr = readDP(dp);
wr = call(wr, rd); wr = call(wr, rd);
op != &SPC700::op_cmp ? writeDP(dp, wr) : io(); op != &SPC700::op_cmp ? writeDP(dp, wr) : idle();
} }
auto SPC700::op_write_ix_iy(fpb op) { auto SPC700::op_write_ix_iy(fpb op) {
io(); idle();
rd = readDP(regs.y); rd = readDP(regs.y);
wr = readDP(regs.x); wr = readDP(regs.x);
wr = call(wr, rd); wr = call(wr, rd);
op != &SPC700::op_cmp ? writeDP(regs.x, wr) : io(); op != &SPC700::op_cmp ? writeDP(regs.x, wr) : idle();
} }
// //
@ -259,10 +259,10 @@ auto SPC700::op_bne_dp() {
dp = readPC(); dp = readPC();
sp = readDP(dp); sp = readDP(dp);
rd = readPC(); rd = readPC();
io(); idle();
if(regs.a == sp) return; if(regs.a == sp) return;
io(); idle();
io(); idle();
regs.pc += (int8)rd; regs.pc += (int8)rd;
} }
@ -272,38 +272,38 @@ auto SPC700::op_bne_dpdec() {
writeDP(dp, --wr); writeDP(dp, --wr);
rd = readPC(); rd = readPC();
if(wr == 0) return; if(wr == 0) return;
io(); idle();
io(); idle();
regs.pc += (int8)rd; regs.pc += (int8)rd;
} }
auto SPC700::op_bne_dpx() { auto SPC700::op_bne_dpx() {
dp = readPC(); dp = readPC();
io(); idle();
sp = readDP(dp + regs.x); sp = readDP(dp + regs.x);
rd = readPC(); rd = readPC();
io(); idle();
if(regs.a == sp) return; if(regs.a == sp) return;
io(); idle();
io(); idle();
regs.pc += (int8)rd; regs.pc += (int8)rd;
} }
auto SPC700::op_bne_ydec() { auto SPC700::op_bne_ydec() {
rd = readPC(); rd = readPC();
io(); idle();
io(); idle();
if(--regs.y == 0) return; if(--regs.y == 0) return;
io(); idle();
io(); idle();
regs.pc += (int8)rd; regs.pc += (int8)rd;
} }
auto SPC700::op_brk() { auto SPC700::op_brk() {
rd.l = read(0xffde); rd.l = read(0xffde);
rd.h = read(0xffdf); rd.h = read(0xffdf);
io(); idle();
io(); idle();
writeSP(regs.pc.h); writeSP(regs.pc.h);
writeSP(regs.pc.l); writeSP(regs.pc.l);
writeSP(regs.p); writeSP(regs.p);
@ -313,20 +313,20 @@ auto SPC700::op_brk() {
} }
auto SPC700::op_clv() { auto SPC700::op_clv() {
io(); idle();
regs.p.v = 0; regs.p.v = 0;
regs.p.h = 0; regs.p.h = 0;
} }
auto SPC700::op_cmc() { auto SPC700::op_cmc() {
io(); idle();
io(); idle();
regs.p.c = !regs.p.c; regs.p.c = !regs.p.c;
} }
auto SPC700::op_daa() { auto SPC700::op_daa() {
io(); idle();
io(); idle();
if(regs.p.c || (regs.a) > 0x99) { if(regs.p.c || (regs.a) > 0x99) {
regs.a += 0x60; regs.a += 0x60;
regs.p.c = 1; regs.p.c = 1;
@ -339,8 +339,8 @@ auto SPC700::op_daa() {
} }
auto SPC700::op_das() { auto SPC700::op_das() {
io(); idle();
io(); idle();
if(!regs.p.c || (regs.a) > 0x99) { if(!regs.p.c || (regs.a) > 0x99) {
regs.a -= 0x60; regs.a -= 0x60;
regs.p.c = 0; regs.p.c = 0;
@ -353,17 +353,17 @@ auto SPC700::op_das() {
} }
auto SPC700::op_div_ya_x() { auto SPC700::op_div_ya_x() {
io(); idle();
io(); idle();
io(); idle();
io(); idle();
io(); idle();
io(); idle();
io(); idle();
io(); idle();
io(); idle();
io(); idle();
io(); idle();
ya = regs.ya; ya = regs.ya;
//overflow set if quotient >= 256 //overflow set if quotient >= 256
regs.p.v = (regs.y >= regs.x); regs.p.v = (regs.y >= regs.x);
@ -392,7 +392,7 @@ auto SPC700::op_jmp_addr() {
auto SPC700::op_jmp_iaddrx() { auto SPC700::op_jmp_iaddrx() {
dp.l = readPC(); dp.l = readPC();
dp.h = readPC(); dp.h = readPC();
io(); idle();
dp += regs.x; dp += regs.x;
rd.l = read(dp++); rd.l = read(dp++);
rd.h = read(dp++); rd.h = read(dp++);
@ -401,8 +401,8 @@ auto SPC700::op_jmp_iaddrx() {
auto SPC700::op_jsp_dp() { auto SPC700::op_jsp_dp() {
rd = readPC(); rd = readPC();
io(); idle();
io(); idle();
writeSP(regs.pc.h); writeSP(regs.pc.h);
writeSP(regs.pc.l); writeSP(regs.pc.l);
regs.pc = 0xff00 | rd; regs.pc = 0xff00 | rd;
@ -411,9 +411,9 @@ auto SPC700::op_jsp_dp() {
auto SPC700::op_jsr_addr() { auto SPC700::op_jsr_addr() {
rd.l = readPC(); rd.l = readPC();
rd.h = readPC(); rd.h = readPC();
io(); idle();
io(); idle();
io(); idle();
writeSP(regs.pc.h); writeSP(regs.pc.h);
writeSP(regs.pc.l); writeSP(regs.pc.l);
regs.pc = rd; regs.pc = rd;
@ -423,31 +423,31 @@ auto SPC700::op_jst() {
dp = 0xffde - ((opcode >> 4) << 1); dp = 0xffde - ((opcode >> 4) << 1);
rd.l = read(dp++); rd.l = read(dp++);
rd.h = read(dp++); rd.h = read(dp++);
io(); idle();
io(); idle();
io(); idle();
writeSP(regs.pc.h); writeSP(regs.pc.h);
writeSP(regs.pc.l); writeSP(regs.pc.l);
regs.pc = rd; regs.pc = rd;
} }
auto SPC700::op_lda_ixinc() { auto SPC700::op_lda_ixinc() {
io(); idle();
regs.a = readDP(regs.x++); regs.a = readDP(regs.x++);
io(); idle();
regs.p.n = regs.a & 0x80; regs.p.n = regs.a & 0x80;
regs.p.z = regs.a == 0; regs.p.z = regs.a == 0;
} }
auto SPC700::op_mul_ya() { auto SPC700::op_mul_ya() {
io(); idle();
io(); idle();
io(); idle();
io(); idle();
io(); idle();
io(); idle();
io(); idle();
io(); idle();
ya = regs.y * regs.a; ya = regs.y * regs.a;
regs.a = ya; regs.a = ya;
regs.y = ya >> 8; regs.y = ya >> 8;
@ -457,12 +457,12 @@ auto SPC700::op_mul_ya() {
} }
auto SPC700::op_nop() { auto SPC700::op_nop() {
io(); idle();
} }
auto SPC700::op_plp() { auto SPC700::op_plp() {
io(); idle();
io(); idle();
regs.p = readSP(); regs.p = readSP();
} }
@ -470,22 +470,22 @@ auto SPC700::op_rti() {
regs.p = readSP(); regs.p = readSP();
rd.l = readSP(); rd.l = readSP();
rd.h = readSP(); rd.h = readSP();
io(); idle();
io(); idle();
regs.pc = rd; regs.pc = rd;
} }
auto SPC700::op_rts() { auto SPC700::op_rts() {
rd.l = readSP(); rd.l = readSP();
rd.h = readSP(); rd.h = readSP();
io(); idle();
io(); idle();
regs.pc = rd; regs.pc = rd;
} }
auto SPC700::op_sta_idpx() { auto SPC700::op_sta_idpx() {
sp = readPC() + regs.x; sp = readPC() + regs.x;
io(); idle();
dp.l = readDP(sp++); dp.l = readDP(sp++);
dp.h = readDP(sp++); dp.h = readDP(sp++);
read(dp); read(dp);
@ -496,21 +496,21 @@ auto SPC700::op_sta_idpy() {
sp = readPC(); sp = readPC();
dp.l = readDP(sp++); dp.l = readDP(sp++);
dp.h = readDP(sp++); dp.h = readDP(sp++);
io(); idle();
dp += regs.y; dp += regs.y;
read(dp); read(dp);
write(dp, regs.a); write(dp, regs.a);
} }
auto SPC700::op_sta_ix() { auto SPC700::op_sta_ix() {
io(); idle();
readDP(regs.x); readDP(regs.x);
writeDP(regs.x, regs.a); writeDP(regs.x, regs.a);
} }
auto SPC700::op_sta_ixinc() { auto SPC700::op_sta_ixinc() {
io(); idle();
io(); idle();
writeDP(regs.x++, regs.a); writeDP(regs.x++, regs.a);
} }
@ -523,16 +523,16 @@ auto SPC700::op_stw_dp() {
auto SPC700::op_wait() { auto SPC700::op_wait() {
while(true) { while(true) {
io(); idle();
io(); idle();
} }
} }
auto SPC700::op_xcn() { auto SPC700::op_xcn() {
io(); idle();
io(); idle();
io(); idle();
io(); idle();
regs.a = (regs.a >> 4) | (regs.a << 4); regs.a = (regs.a >> 4) | (regs.a << 4);
regs.p.n = regs.a & 0x80; regs.p.n = regs.a & 0x80;
regs.p.z = regs.a == 0; regs.p.z = regs.a == 0;

View File

@ -3,7 +3,7 @@
namespace Processor { namespace Processor {
struct SPC700 { struct SPC700 {
virtual auto io() -> void = 0; virtual auto idle() -> void = 0;
virtual auto read(uint16 addr) -> uint8 = 0; virtual auto read(uint16 addr) -> uint8 = 0;
virtual auto write(uint16 addr, uint8 data) -> void = 0; virtual auto write(uint16 addr, uint8 data) -> void = 0;
virtual auto readDisassembler(uint16 addr) -> uint8 = 0; virtual auto readDisassembler(uint16 addr) -> uint8 = 0;

View File

@ -1,3 +1,5 @@
using format = string_format;
//todo: this is horribly broken in many cases; needs a total rewrite //todo: this is horribly broken in many cases; needs a total rewrite
auto V30MZ::disassemble(uint16 cs, uint16 ip, bool registers, bool bytes) -> string { auto V30MZ::disassemble(uint16 cs, uint16 ip, bool registers, bool bytes) -> string {
string s; string s;

View File

@ -108,7 +108,7 @@ auto SA1::vbrRead(uint24 addr, uint8 data) -> uint8 {
//tick() == 2 clock ticks //tick() == 2 clock ticks
//note: bus conflict delays are not emulated at this time //note: bus conflict delays are not emulated at this time
auto SA1::io() -> void { auto SA1::idle() -> void {
tick(); tick();
} }

View File

@ -30,19 +30,6 @@ auto SA1::main() -> void {
instruction(); instruction();
} }
auto SA1::interrupt() -> void {
read(r.pc.d);
io();
if(!r.e) writeSP(r.pc.b);
writeSP(r.pc.h);
writeSP(r.pc.l);
writeSP(r.e ? (r.p & ~0x10) : r.p);
r.pc.w = r.vector;
r.pc.b = 0x00;
r.p.i = 1;
r.p.d = 0;
}
auto SA1::lastCycle() -> void { auto SA1::lastCycle() -> void {
if(mmio.sa1_nmi && !mmio.sa1_nmicl) { if(mmio.sa1_nmi && !mmio.sa1_nmicl) {
status.interruptPending = true; status.interruptPending = true;

View File

@ -3,7 +3,6 @@ struct SA1 : Processor::R65816, Cothread {
static auto Enter() -> void; static auto Enter() -> void;
auto main() -> void; auto main() -> void;
auto tick() -> void; auto tick() -> void;
auto interrupt() -> void override;
alwaysinline auto triggerIRQ() -> void; alwaysinline auto triggerIRQ() -> void;
alwaysinline auto lastCycle() -> void override; alwaysinline auto lastCycle() -> void override;
@ -47,7 +46,7 @@ struct SA1 : Processor::R65816, Cothread {
auto busWrite(uint24 addr, uint8 data) -> void; auto busWrite(uint24 addr, uint8 data) -> void;
auto vbrRead(uint24 addr, uint8 data = 0) -> uint8; auto vbrRead(uint24 addr, uint8 data = 0) -> uint8;
alwaysinline auto io() -> void override; alwaysinline auto idle() -> void override;
alwaysinline auto read(uint24 addr) -> uint8 override; alwaysinline auto read(uint24 addr) -> uint8 override;
alwaysinline auto write(uint24 addr, uint8 data) -> void override; alwaysinline auto write(uint24 addr, uint8 data) -> void override;

View File

@ -12,25 +12,13 @@ CPU cpu;
#include "serialization.cpp" #include "serialization.cpp"
auto CPU::interruptPending() const -> bool { return status.interruptPending; } auto CPU::interruptPending() const -> bool { return status.interruptPending; }
auto CPU::pio() const -> uint8 { return status.pio; } auto CPU::pio() const -> uint8 { return io.pio; }
auto CPU::joylatch() const -> bool { return status.joypadStrobeLatch; } auto CPU::joylatch() const -> bool { return io.joypadStrobeLatch; }
CPU::CPU() { CPU::CPU() {
PPUcounter::scanline = {&CPU::scanline, this}; PPUcounter::scanline = {&CPU::scanline, this};
} }
auto CPU::step(uint clocks) -> void {
smp.clock -= clocks * (uint64)smp.frequency;
ppu.clock -= clocks;
for(auto coprocessor : coprocessors) {
coprocessor->clock -= clocks * (uint64)coprocessor->frequency;
}
for(auto peripheral : peripherals) {
peripheral->clock -= clocks * (uint64)peripheral->frequency;
}
synchronizePeripherals();
}
auto CPU::synchronizeSMP() -> void { auto CPU::synchronizeSMP() -> void {
if(smp.clock < 0) co_switch(smp.thread); if(smp.clock < 0) co_switch(smp.thread);
} }
@ -68,12 +56,12 @@ auto CPU::main() -> void {
interrupt(); interrupt();
} else if(status.resetPending) { } else if(status.resetPending) {
status.resetPending = false; status.resetPending = false;
addClocks(132); step(132);
r.vector = 0xfffc; r.vector = 0xfffc;
interrupt(); interrupt();
} else if(status.powerPending) { } else if(status.powerPending) {
status.powerPending = false; status.powerPending = false;
addClocks(186); step(186);
r.pc.l = bus.read(0xfffc, r.mdr); r.pc.l = bus.read(0xfffc, r.mdr);
r.pc.h = bus.read(0xfffd, r.mdr); r.pc.h = bus.read(0xfffd, r.mdr);
} }
@ -161,49 +149,47 @@ auto CPU::reset() -> void {
r.vector = 0xfffc; //reset vector address r.vector = 0xfffc; //reset vector address
//$2140-217f //$2140-217f
for(auto& port : status.port) port = 0x00; for(auto& port : io.port) port = 0x00;
//$2181-$2183 //$2181-$2183
status.wramAddress = 0x000000; io.wramAddress = 0x000000;
//$4016-$4017 //$4016-$4017
status.joypadStrobeLatch = 0; io.joypadStrobeLatch = 0;
status.joypad1_bits = ~0;
status.joypad2_bits = ~0;
//$4200 //$4200
status.nmiEnabled = false; io.nmiEnabled = false;
status.hirqEnabled = false; io.hirqEnabled = false;
status.virqEnabled = false; io.virqEnabled = false;
status.autoJoypadPoll = false; io.autoJoypadPoll = false;
//$4201 //$4201
status.pio = 0xff; io.pio = 0xff;
//$4202-$4203 //$4202-$4203
status.wrmpya = 0xff; io.wrmpya = 0xff;
status.wrmpyb = 0xff; io.wrmpyb = 0xff;
//$4204-$4206 //$4204-$4206
status.wrdiva = 0xffff; io.wrdiva = 0xffff;
status.wrdivb = 0xff; io.wrdivb = 0xff;
//$4207-$420a //$4207-$420a
status.hirqPos = 0x01ff; io.hirqPos = 0x01ff;
status.virqPos = 0x01ff; io.virqPos = 0x01ff;
//$420d //$420d
status.romSpeed = 8; io.romSpeed = 8;
//$4214-$4217 //$4214-$4217
status.rddiv = 0x0000; io.rddiv = 0x0000;
status.rdmpy = 0x0000; io.rdmpy = 0x0000;
//$4218-$421f //$4218-$421f
status.joy1 = 0x0000; io.joy1 = 0x0000;
status.joy2 = 0x0000; io.joy2 = 0x0000;
status.joy3 = 0x0000; io.joy3 = 0x0000;
status.joy4 = 0x0000; io.joy4 = 0x0000;
//ALU //ALU
alu.mpyctr = 0; alu.mpyctr = 0;

View File

@ -5,14 +5,13 @@ struct CPU : Processor::R65816, Thread, PPUcounter {
CPU(); CPU();
alwaysinline auto step(uint clocks) -> void; auto synchronizeSMP() -> void;
alwaysinline auto synchronizeSMP() -> void;
auto synchronizePPU() -> void; auto synchronizePPU() -> void;
auto synchronizeCoprocessors() -> void; auto synchronizeCoprocessors() -> void;
auto synchronizePeripherals() -> void; auto synchronizePeripherals() -> void;
auto portRead(uint2 port) const -> uint8; auto readPort(uint2 port) const -> uint8;
auto portWrite(uint2 port, uint8 data) -> void; auto writePort(uint2 port, uint8 data) -> void;
static auto Enter() -> void; static auto Enter() -> void;
auto main() -> void; auto main() -> void;
@ -21,7 +20,7 @@ struct CPU : Processor::R65816, Thread, PPUcounter {
auto reset() -> void; auto reset() -> void;
//dma.cpp //dma.cpp
auto dmaAddClocks(uint clocks) -> void; auto dmaStep(uint clocks) -> void;
auto dmaTransferValid(uint8 bbus, uint24 abus) -> bool; auto dmaTransferValid(uint8 bbus, uint24 abus) -> bool;
auto dmaAddressValid(uint24 abus) -> bool; auto dmaAddressValid(uint24 abus) -> bool;
auto dmaRead(uint24 abus) -> uint8; auto dmaRead(uint24 abus) -> uint8;
@ -46,7 +45,7 @@ struct CPU : Processor::R65816, Thread, PPUcounter {
auto hdmaInit() -> void; auto hdmaInit() -> void;
//memory.cpp //memory.cpp
auto io() -> void override; auto idle() -> void override;
auto read(uint24 addr) -> uint8 override; auto read(uint24 addr) -> uint8 override;
auto write(uint24 addr, uint8 data) -> void override; auto write(uint24 addr, uint8 data) -> void override;
alwaysinline auto speed(uint24 addr) const -> uint; alwaysinline auto speed(uint24 addr) const -> uint;
@ -63,7 +62,7 @@ struct CPU : Processor::R65816, Thread, PPUcounter {
//timing.cpp //timing.cpp
auto dmaCounter() const -> uint; auto dmaCounter() const -> uint;
auto addClocks(uint clocks) -> void; auto step(uint clocks) -> void;
auto scanline() -> void; auto scanline() -> void;
alwaysinline auto aluEdge() -> void; alwaysinline auto aluEdge() -> void;
@ -138,8 +137,9 @@ privileged:
bool autoJoypadLatch; bool autoJoypadLatch;
uint autoJoypadCounter; uint autoJoypadCounter;
uint autoJoypadClock; uint autoJoypadClock;
} status;
//MMIO struct IO {
//$2140-217f //$2140-217f
uint8 port[4]; uint8 port[4];
@ -148,8 +148,6 @@ privileged:
//$4016-$4017 //$4016-$4017
bool joypadStrobeLatch; bool joypadStrobeLatch;
uint32 joypad1_bits;
uint32 joypad2_bits;
//$4200 //$4200
bool nmiEnabled; bool nmiEnabled;
@ -184,7 +182,7 @@ privileged:
uint16 joy2; uint16 joy2;
uint16 joy3; uint16 joy3;
uint16 joy4; uint16 joy4;
} status; } io;
struct ALU { struct ALU {
uint mpyctr; uint mpyctr;
@ -218,8 +216,8 @@ privileged:
//$43x5-$43x6 //$43x5-$43x6
union { union {
uint16 transferSize = 0; uint16 transferSize;
uint16_t indirectAddress; uint16 indirectAddress;
}; };
//$43x7 //$43x7
@ -237,6 +235,8 @@ privileged:
//internal state //internal state
bool hdmaCompleted; bool hdmaCompleted;
bool hdmaDoTransfer; bool hdmaDoTransfer;
Channel() : transferSize(0) {}
} channel[8]; } channel[8];
struct Pipe { struct Pipe {

View File

@ -1,6 +1,6 @@
auto CPU::dmaAddClocks(uint clocks) -> void { auto CPU::dmaStep(uint clocks) -> void {
status.dmaClocks += clocks; status.dmaClocks += clocks;
addClocks(clocks); step(clocks);
} }
//============= //=============
@ -41,14 +41,14 @@ auto CPU::dmaWrite(bool valid, uint addr, uint8 data) -> void {
auto CPU::dmaTransfer(bool direction, uint8 bbus, uint24 abus) -> void { auto CPU::dmaTransfer(bool direction, uint8 bbus, uint24 abus) -> void {
if(direction == 0) { if(direction == 0) {
dmaAddClocks(4); dmaStep(4);
r.mdr = dmaRead(abus); r.mdr = dmaRead(abus);
dmaAddClocks(4); dmaStep(4);
dmaWrite(dmaTransferValid(bbus, abus), 0x2100 | bbus, r.mdr); dmaWrite(dmaTransferValid(bbus, abus), 0x2100 | bbus, r.mdr);
} else { } else {
dmaAddClocks(4); dmaStep(4);
r.mdr = dmaTransferValid(bbus, abus) ? bus.read(0x2100 | bbus, r.mdr) : (uint8)0x00; r.mdr = dmaTransferValid(bbus, abus) ? bus.read(0x2100 | bbus, r.mdr) : (uint8)0x00;
dmaAddClocks(4); dmaStep(4);
dmaWrite(dmaAddressValid(abus), abus, r.mdr); dmaWrite(dmaAddressValid(abus), abus, r.mdr);
} }
} }
@ -131,7 +131,7 @@ auto CPU::hdmaActiveChannels() -> uint {
//============== //==============
auto CPU::dmaRun() -> void { auto CPU::dmaRun() -> void {
dmaAddClocks(8); dmaStep(8);
dmaWrite(false); dmaWrite(false);
dmaEdge(); dmaEdge();
@ -144,7 +144,7 @@ auto CPU::dmaRun() -> void {
dmaEdge(); dmaEdge();
} while(channel[n].dmaEnabled && --channel[n].transferSize); } while(channel[n].dmaEnabled && --channel[n].transferSize);
dmaAddClocks(8); dmaStep(8);
dmaWrite(false); dmaWrite(false);
dmaEdge(); dmaEdge();
@ -155,9 +155,9 @@ auto CPU::dmaRun() -> void {
} }
auto CPU::hdmaUpdate(uint n) -> void { auto CPU::hdmaUpdate(uint n) -> void {
dmaAddClocks(4); dmaStep(4);
r.mdr = dmaRead(channel[n].sourceBank << 16 | channel[n].hdmaAddress); r.mdr = dmaRead(channel[n].sourceBank << 16 | channel[n].hdmaAddress);
dmaAddClocks(4); dmaStep(4);
dmaWrite(false); dmaWrite(false);
if((channel[n].lineCounter & 0x7f) == 0) { if((channel[n].lineCounter & 0x7f) == 0) {
@ -168,18 +168,18 @@ auto CPU::hdmaUpdate(uint n) -> void {
channel[n].hdmaDoTransfer = !channel[n].hdmaCompleted; channel[n].hdmaDoTransfer = !channel[n].hdmaCompleted;
if(channel[n].indirect) { if(channel[n].indirect) {
dmaAddClocks(4); dmaStep(4);
r.mdr = dmaRead(hdmaAddress(n)); r.mdr = dmaRead(hdmaAddress(n));
channel[n].indirectAddress = r.mdr << 8; channel[n].indirectAddress = r.mdr << 8;
dmaAddClocks(4); dmaStep(4);
dmaWrite(false); dmaWrite(false);
if(!channel[n].hdmaCompleted || hdmaActiveAfter(n)) { if(!channel[n].hdmaCompleted || hdmaActiveAfter(n)) {
dmaAddClocks(4); dmaStep(4);
r.mdr = dmaRead(hdmaAddress(n)); r.mdr = dmaRead(hdmaAddress(n));
channel[n].indirectAddress >>= 8; channel[n].indirectAddress >>= 8;
channel[n].indirectAddress |= r.mdr << 8; channel[n].indirectAddress |= r.mdr << 8;
dmaAddClocks(4); dmaStep(4);
dmaWrite(false); dmaWrite(false);
} }
} }
@ -187,7 +187,7 @@ auto CPU::hdmaUpdate(uint n) -> void {
} }
auto CPU::hdmaRun() -> void { auto CPU::hdmaRun() -> void {
dmaAddClocks(8); dmaStep(8);
dmaWrite(false); dmaWrite(false);
for(auto n : range(8)) { for(auto n : range(8)) {
@ -223,7 +223,7 @@ auto CPU::hdmaInitReset() -> void {
} }
auto CPU::hdmaInit() -> void { auto CPU::hdmaInit() -> void {
dmaAddClocks(8); dmaStep(8);
dmaWrite(false); dmaWrite(false);
for(auto n : range(8)) { for(auto n : range(8)) {

View File

@ -8,7 +8,7 @@ auto CPU::readCPU(uint24 addr, uint8 data) -> uint8 {
//WMDATA //WMDATA
case 0x2180: { case 0x2180: {
return bus.read(0x7e0000 | status.wramAddress++, r.mdr); return bus.read(0x7e0000 | io.wramAddress++, r.mdr);
} }
//JOYSER0 //JOYSER0
@ -65,37 +65,37 @@ auto CPU::readCPU(uint24 addr, uint8 data) -> uint8 {
//RDIO //RDIO
case 0x4213: { case 0x4213: {
return status.pio; return io.pio;
} }
//RDDIVL //RDDIVL
case 0x4214: { case 0x4214: {
return status.rddiv.byte(0); return io.rddiv.byte(0);
} }
//RDDIVH //RDDIVH
case 0x4215: { case 0x4215: {
return status.rddiv.byte(1); return io.rddiv.byte(1);
} }
//RDMPYL //RDMPYL
case 0x4216: { case 0x4216: {
return status.rdmpy.byte(0); return io.rdmpy.byte(0);
} }
//RDMPYH //RDMPYH
case 0x4217: { case 0x4217: {
return status.rdmpy.byte(1); return io.rdmpy.byte(1);
} }
case 0x4218: return status.joy1.byte(0); //JOY1L case 0x4218: return io.joy1.byte(0); //JOY1L
case 0x4219: return status.joy1.byte(1); //JOY1H case 0x4219: return io.joy1.byte(1); //JOY1H
case 0x421a: return status.joy2.byte(0); //JOY2L case 0x421a: return io.joy2.byte(0); //JOY2L
case 0x421b: return status.joy2.byte(1); //JOY2H case 0x421b: return io.joy2.byte(1); //JOY2H
case 0x421c: return status.joy3.byte(0); //JOY3L case 0x421c: return io.joy3.byte(0); //JOY3L
case 0x421d: return status.joy3.byte(1); //JOY3H case 0x421d: return io.joy3.byte(1); //JOY3H
case 0x421e: return status.joy4.byte(0); //JOY4L case 0x421e: return io.joy4.byte(0); //JOY4L
case 0x421f: return status.joy4.byte(1); //JOY4H case 0x421f: return io.joy4.byte(1); //JOY4H
} }
@ -158,7 +158,7 @@ auto CPU::readDMA(uint24 addr, uint8 data) -> uint8 {
auto CPU::writeAPU(uint24 addr, uint8 data) -> void { auto CPU::writeAPU(uint24 addr, uint8 data) -> void {
synchronizeSMP(); synchronizeSMP();
return portWrite(addr.bits(0,1), data); return writePort(addr.bits(0,1), data);
} }
auto CPU::writeCPU(uint24 addr, uint8 data) -> void { auto CPU::writeCPU(uint24 addr, uint8 data) -> void {
@ -166,12 +166,12 @@ auto CPU::writeCPU(uint24 addr, uint8 data) -> void {
//WMDATA //WMDATA
case 0x2180: { case 0x2180: {
return bus.write(0x7e0000 | status.wramAddress++, data); return bus.write(0x7e0000 | io.wramAddress++, data);
} }
case 0x2181: status.wramAddress.bits( 0, 7) = data; return; //WMADDL case 0x2181: io.wramAddress.bits( 0, 7) = data; return; //WMADDL
case 0x2182: status.wramAddress.bits( 8,15) = data; return; //WMADDM case 0x2182: io.wramAddress.bits( 8,15) = data; return; //WMADDM
case 0x2183: status.wramAddress.bit (16 ) = data.bit(0); return; //WMADDH case 0x2183: io.wramAddress.bit (16 ) = data.bit(0); return; //WMADDH
//JOYSER0 //JOYSER0
case 0x4016: { case 0x4016: {
@ -185,54 +185,54 @@ auto CPU::writeCPU(uint24 addr, uint8 data) -> void {
//NMITIMEN //NMITIMEN
case 0x4200: { case 0x4200: {
status.autoJoypadPoll = data.bit(0); io.autoJoypadPoll = data.bit(0);
nmitimenUpdate(data); nmitimenUpdate(data);
return; return;
} }
//WRIO //WRIO
case 0x4201: { case 0x4201: {
if(status.pio.bit(7) && !data.bit(7)) ppu.latchCounters(); if(io.pio.bit(7) && !data.bit(7)) ppu.latchCounters();
status.pio = data; io.pio = data;
return; return;
} }
//WRMPYA //WRMPYA
case 0x4202: status.wrmpya = data; return; case 0x4202: io.wrmpya = data; return;
//WRMPYB //WRMPYB
case 0x4203: { case 0x4203: {
status.rdmpy = 0; io.rdmpy = 0;
if(alu.mpyctr || alu.divctr) return; if(alu.mpyctr || alu.divctr) return;
status.wrmpyb = data; io.wrmpyb = data;
status.rddiv = (status.wrmpyb << 8) | status.wrmpya; io.rddiv = (io.wrmpyb << 8) | io.wrmpya;
alu.mpyctr = 8; //perform multiplication over the next eight cycles alu.mpyctr = 8; //perform multiplication over the next eight cycles
alu.shift = status.wrmpyb; alu.shift = io.wrmpyb;
return; return;
} }
case 0x4204: { status.wrdiva.byte(0) = data; return; } //WRDIVL case 0x4204: { io.wrdiva.byte(0) = data; return; } //WRDIVL
case 0x4205: { status.wrdiva.byte(1) = data; return; } //WRDIVH case 0x4205: { io.wrdiva.byte(1) = data; return; } //WRDIVH
//WRDIVB //WRDIVB
case 0x4206: { case 0x4206: {
status.rdmpy = status.wrdiva; io.rdmpy = io.wrdiva;
if(alu.mpyctr || alu.divctr) return; if(alu.mpyctr || alu.divctr) return;
status.wrdivb = data; io.wrdivb = data;
alu.divctr = 16; //perform division over the next sixteen cycles alu.divctr = 16; //perform division over the next sixteen cycles
alu.shift = status.wrdivb << 16; alu.shift = io.wrdivb << 16;
return; return;
} }
case 0x4207: status.hirqPos.bits(0,7) = data; return; //HTIMEL case 0x4207: io.hirqPos.bits(0,7) = data; return; //HTIMEL
case 0x4208: status.hirqPos.bit (8 ) = data.bit(0); return; //HTIMEH case 0x4208: io.hirqPos.bit (8 ) = data.bit(0); return; //HTIMEH
case 0x4209: status.virqPos.bits(0,7) = data; return; //VTIMEL case 0x4209: io.virqPos.bits(0,7) = data; return; //VTIMEL
case 0x420a: status.virqPos.bit (8 ) = data.bit(0); return; //VTIMEH case 0x420a: io.virqPos.bit (8 ) = data.bit(0); return; //VTIMEH
//DMAEN //DMAEN
case 0x420b: { case 0x420b: {
@ -249,7 +249,7 @@ auto CPU::writeCPU(uint24 addr, uint8 data) -> void {
//MEMSEL //MEMSEL
case 0x420d: { case 0x420d: {
status.romSpeed = data.bit(0) ? 6 : 8; io.romSpeed = data.bit(0) ? 6 : 8;
return; return;
} }

View File

@ -7,7 +7,7 @@ auto CPU::pollInterrupts() -> void {
//NMI hold //NMI hold
if(status.nmiHold) { if(status.nmiHold) {
status.nmiHold = false; status.nmiHold = false;
if(status.nmiEnabled) status.nmiTransition = true; if(io.nmiEnabled) status.nmiTransition = true;
} }
//NMI test //NMI test
@ -25,15 +25,15 @@ auto CPU::pollInterrupts() -> void {
//IRQ hold //IRQ hold
status.irqHold = false; status.irqHold = false;
if(status.irqLine) { if(status.irqLine) {
if(status.virqEnabled || status.hirqEnabled) status.irqTransition = true; if(io.virqEnabled || io.hirqEnabled) status.irqTransition = true;
} }
//IRQ test //IRQ test
bool irqValid = status.virqEnabled || status.hirqEnabled; bool irqValid = io.virqEnabled || io.hirqEnabled;
if(irqValid) { if(irqValid) {
if((status.virqEnabled && vcounter(10) != (status.virqPos)) if((io.virqEnabled && vcounter(10) != (io.virqPos))
|| (status.hirqEnabled && hcounter(10) != (status.hirqPos + 1) * 4) || (io.hirqEnabled && hcounter(10) != (io.hirqPos + 1) * 4)
|| (status.virqPos && vcounter(6) == 0) //IRQs cannot trigger on last dot of field || (io.virqPos && vcounter(6) == 0) //IRQs cannot trigger on last dot of field
) irqValid = false; ) irqValid = false;
} }
if(!status.irqValid && irqValid) { if(!status.irqValid && irqValid) {
@ -45,24 +45,24 @@ auto CPU::pollInterrupts() -> void {
} }
auto CPU::nmitimenUpdate(uint8 data) -> void { auto CPU::nmitimenUpdate(uint8 data) -> void {
bool nmiEnabled = status.nmiEnabled; bool nmiEnabled = io.nmiEnabled;
bool virqEnabled = status.virqEnabled; bool virqEnabled = io.virqEnabled;
bool hirqEnabled = status.hirqEnabled; bool hirqEnabled = io.hirqEnabled;
status.nmiEnabled = data & 0x80; io.nmiEnabled = data & 0x80;
status.virqEnabled = data & 0x20; io.virqEnabled = data & 0x20;
status.hirqEnabled = data & 0x10; io.hirqEnabled = data & 0x10;
//0->1 edge sensitive transition //0->1 edge sensitive transition
if(!nmiEnabled && status.nmiEnabled && status.nmiLine) { if(!nmiEnabled && io.nmiEnabled && status.nmiLine) {
status.nmiTransition = true; status.nmiTransition = true;
} }
//?->1 level sensitive transition //?->1 level sensitive transition
if(status.virqEnabled && !status.hirqEnabled && status.irqLine) { if(io.virqEnabled && !io.hirqEnabled && status.irqLine) {
status.irqTransition = true; status.irqTransition = true;
} }
if(!status.virqEnabled && !status.hirqEnabled) { if(!io.virqEnabled && !io.hirqEnabled) {
status.irqLine = false; status.irqLine = false;
status.irqTransition = false; status.irqTransition = false;
} }

View File

@ -2,7 +2,7 @@
auto CPU::stepAutoJoypadPoll() -> void { auto CPU::stepAutoJoypadPoll() -> void {
if(vcounter() >= ppu.vdisp()) { if(vcounter() >= ppu.vdisp()) {
//cache enable state at first iteration //cache enable state at first iteration
if(status.autoJoypadCounter == 0) status.autoJoypadLatch = status.autoJoypadPoll; if(status.autoJoypadCounter == 0) status.autoJoypadLatch = io.autoJoypadPoll;
status.autoJoypadActive = status.autoJoypadCounter <= 15; status.autoJoypadActive = status.autoJoypadCounter <= 15;
if(status.autoJoypadActive && status.autoJoypadLatch) { if(status.autoJoypadActive && status.autoJoypadLatch) {
@ -16,10 +16,10 @@ auto CPU::stepAutoJoypadPoll() -> void {
uint2 port0 = SuperFamicom::peripherals.controllerPort1->data(); uint2 port0 = SuperFamicom::peripherals.controllerPort1->data();
uint2 port1 = SuperFamicom::peripherals.controllerPort2->data(); uint2 port1 = SuperFamicom::peripherals.controllerPort2->data();
status.joy1 = status.joy1 << 1 | port0.bit(0); io.joy1 = io.joy1 << 1 | port0.bit(0);
status.joy2 = status.joy2 << 1 | port1.bit(0); io.joy2 = io.joy2 << 1 | port1.bit(0);
status.joy3 = status.joy3 << 1 | port0.bit(1); io.joy3 = io.joy3 << 1 | port0.bit(1);
status.joy4 = status.joy4 << 1 | port1.bit(1); io.joy4 = io.joy4 << 1 | port1.bit(1);
} }
status.autoJoypadCounter++; status.autoJoypadCounter++;

View File

@ -1,24 +1,24 @@
auto CPU::portRead(uint2 port) const -> uint8 { auto CPU::readPort(uint2 port) const -> uint8 {
return status.port[port]; return io.port[port];
} }
auto CPU::portWrite(uint2 port, uint8 data) -> void { auto CPU::writePort(uint2 port, uint8 data) -> void {
status.port[port] = data; io.port[port] = data;
} }
auto CPU::io() -> void { auto CPU::idle() -> void {
status.clockCount = 6; status.clockCount = 6;
dmaEdge(); dmaEdge();
addClocks(6); step(6);
aluEdge(); aluEdge();
} }
auto CPU::read(uint24 addr) -> uint8 { auto CPU::read(uint24 addr) -> uint8 {
status.clockCount = speed(addr); status.clockCount = speed(addr);
dmaEdge(); dmaEdge();
addClocks(status.clockCount - 4); step(status.clockCount - 4);
r.mdr = bus.read(addr, r.mdr); r.mdr = bus.read(addr, r.mdr);
addClocks(4); step(4);
aluEdge(); aluEdge();
return r.mdr; return r.mdr;
} }
@ -27,15 +27,12 @@ auto CPU::write(uint24 addr, uint8 data) -> void {
aluEdge(); aluEdge();
status.clockCount = speed(addr); status.clockCount = speed(addr);
dmaEdge(); dmaEdge();
addClocks(status.clockCount); step(status.clockCount);
bus.write(addr, r.mdr = data); bus.write(addr, r.mdr = data);
} }
auto CPU::speed(uint24 addr) const -> uint { auto CPU::speed(uint24 addr) const -> uint {
if(addr & 0x408000) { if(addr & 0x408000) return addr & 0x800000 ? io.romSpeed : 8;
if(addr & 0x800000) return status.romSpeed;
return 8;
}
if((addr + 0x6000) & 0x4000) return 8; if((addr + 0x6000) & 0x4000) return 8;
if((addr - 0x4000) & 0x7e00) return 6; if((addr - 0x4000) & 0x7e00) return 6;
return 12; return 12;

View File

@ -50,39 +50,37 @@ auto CPU::serialize(serializer& s) -> void {
s.integer(status.autoJoypadCounter); s.integer(status.autoJoypadCounter);
s.integer(status.autoJoypadClock); s.integer(status.autoJoypadClock);
s.array(status.port); s.array(io.port);
s.integer(status.wramAddress); s.integer(io.wramAddress);
s.integer(status.joypadStrobeLatch); s.integer(io.joypadStrobeLatch);
s.integer(status.joypad1_bits);
s.integer(status.joypad2_bits);
s.integer(status.nmiEnabled); s.integer(io.nmiEnabled);
s.integer(status.hirqEnabled); s.integer(io.hirqEnabled);
s.integer(status.virqEnabled); s.integer(io.virqEnabled);
s.integer(status.autoJoypadPoll); s.integer(io.autoJoypadPoll);
s.integer(status.pio); s.integer(io.pio);
s.integer(status.wrmpya); s.integer(io.wrmpya);
s.integer(status.wrmpyb); s.integer(io.wrmpyb);
s.integer(status.wrdiva); s.integer(io.wrdiva);
s.integer(status.wrdivb); s.integer(io.wrdivb);
s.integer(status.hirqPos); s.integer(io.hirqPos);
s.integer(status.virqPos); s.integer(io.virqPos);
s.integer(status.romSpeed); s.integer(io.romSpeed);
s.integer(status.rddiv); s.integer(io.rddiv);
s.integer(status.rdmpy); s.integer(io.rdmpy);
s.integer(status.joy1); s.integer(io.joy1);
s.integer(status.joy2); s.integer(io.joy2);
s.integer(status.joy3); s.integer(io.joy3);
s.integer(status.joy4); s.integer(io.joy4);
s.integer(alu.mpyctr); s.integer(alu.mpyctr);
s.integer(alu.divctr); s.integer(alu.divctr);

View File

@ -2,7 +2,7 @@ auto CPU::dmaCounter() const -> uint {
return (status.dmaCounter + hcounter()) & 7; return (status.dmaCounter + hcounter()) & 7;
} }
auto CPU::addClocks(uint clocks) -> void { auto CPU::step(uint clocks) -> void {
status.irqLock = false; status.irqLock = false;
uint ticks = clocks >> 1; uint ticks = clocks >> 1;
while(ticks--) { while(ticks--) {
@ -10,7 +10,15 @@ auto CPU::addClocks(uint clocks) -> void {
if(hcounter() & 2) pollInterrupts(); if(hcounter() & 2) pollInterrupts();
} }
step(clocks); smp.clock -= clocks * (uint64)smp.frequency;
ppu.clock -= clocks;
for(auto coprocessor : coprocessors) {
coprocessor->clock -= clocks * (uint64)coprocessor->frequency;
}
for(auto peripheral : peripherals) {
peripheral->clock -= clocks * (uint64)peripheral->frequency;
}
synchronizePeripherals();
status.autoJoypadClock += clocks; status.autoJoypadClock += clocks;
if(status.autoJoypadClock >= 256) { if(status.autoJoypadClock >= 256) {
@ -20,7 +28,7 @@ auto CPU::addClocks(uint clocks) -> void {
if(!status.dramRefreshed && hcounter() >= status.dramRefreshPosition) { if(!status.dramRefreshed && hcounter() >= status.dramRefreshPosition) {
status.dramRefreshed = true; status.dramRefreshed = true;
addClocks(40); step(40);
} }
#if defined(DEBUGGER) #if defined(DEBUGGER)
@ -62,18 +70,18 @@ auto CPU::scanline() -> void {
auto CPU::aluEdge() -> void { auto CPU::aluEdge() -> void {
if(alu.mpyctr) { if(alu.mpyctr) {
alu.mpyctr--; alu.mpyctr--;
if(status.rddiv & 1) status.rdmpy += alu.shift; if(io.rddiv & 1) io.rdmpy += alu.shift;
status.rddiv >>= 1; io.rddiv >>= 1;
alu.shift <<= 1; alu.shift <<= 1;
} }
if(alu.divctr) { if(alu.divctr) {
alu.divctr--; alu.divctr--;
status.rddiv <<= 1; io.rddiv <<= 1;
alu.shift >>= 1; alu.shift >>= 1;
if(status.rdmpy >= alu.shift) { if(io.rdmpy >= alu.shift) {
status.rdmpy -= alu.shift; io.rdmpy -= alu.shift;
status.rddiv |= 1; io.rddiv |= 1;
} }
} }
} }
@ -92,11 +100,11 @@ auto CPU::dmaEdge() -> void {
status.hdmaPending = false; status.hdmaPending = false;
if(hdmaEnabledChannels()) { if(hdmaEnabledChannels()) {
if(!dmaEnabledChannels()) { if(!dmaEnabledChannels()) {
dmaAddClocks(8 - dmaCounter()); dmaStep(8 - dmaCounter());
} }
status.hdmaMode == 0 ? hdmaInit() : hdmaRun(); status.hdmaMode == 0 ? hdmaInit() : hdmaRun();
if(!dmaEnabledChannels()) { if(!dmaEnabledChannels()) {
addClocks(status.clockCount - (status.dmaClocks % status.clockCount)); step(status.clockCount - (status.dmaClocks % status.clockCount));
status.dmaActive = false; status.dmaActive = false;
} }
} }
@ -105,9 +113,9 @@ auto CPU::dmaEdge() -> void {
if(status.dmaPending) { if(status.dmaPending) {
status.dmaPending = false; status.dmaPending = false;
if(dmaEnabledChannels()) { if(dmaEnabledChannels()) {
dmaAddClocks(8 - dmaCounter()); dmaStep(8 - dmaCounter());
dmaRun(); dmaRun();
addClocks(status.clockCount - (status.dmaClocks % status.clockCount)); step(status.clockCount - (status.dmaClocks % status.clockCount));
status.dmaActive = false; status.dmaActive = false;
} }
} }

View File

@ -244,8 +244,8 @@ auto Interface::cheatSet(const lstring& list) -> void {
lstring codes = codeset.split("+"); lstring codes = codeset.split("+");
for(auto& code : codes) { for(auto& code : codes) {
lstring part = code.split("/"); lstring part = code.split("/");
if(part.size() == 2) GameBoy::cheat.append(hex(part[0]), hex(part[1])); if(part.size() == 2) GameBoy::cheat.append(part[0].hex(), part[1].hex());
if(part.size() == 3) GameBoy::cheat.append(hex(part[0]), hex(part[1]), hex(part[2])); if(part.size() == 3) GameBoy::cheat.append(part[0].hex(), part[1].hex(), part[2].hex());
} }
} }
return; return;
@ -256,8 +256,8 @@ auto Interface::cheatSet(const lstring& list) -> void {
lstring codes = codeset.split("+"); lstring codes = codeset.split("+");
for(auto& code : codes) { for(auto& code : codes) {
lstring part = code.split("/"); lstring part = code.split("/");
if(part.size() == 2) cheat.append(hex(part[0]), hex(part[1])); if(part.size() == 2) cheat.append(part[0].hex(), part[1].hex());
if(part.size() == 3) cheat.append(hex(part[0]), hex(part[1]), hex(part[2])); if(part.size() == 3) cheat.append(part[0].hex(), part[1].hex(), part[2].hex());
} }
} }
} }

View File

@ -35,7 +35,6 @@ auto Bus::map(
while(counter[id]) { while(counter[id]) {
if(++id >= 256) return print("SFC error: bus map exhausted\n"); if(++id >= 256) return print("SFC error: bus map exhausted\n");
} }
//print("map[", hex(id, 2), "] => ", addr, "\n");
reader[id] = read; reader[id] = read;
writer[id] = write; writer[id] = write;
@ -47,10 +46,10 @@ auto Bus::map(
for(auto& addr : addrs) { for(auto& addr : addrs) {
auto bankRange = bank.split("-", 1L); auto bankRange = bank.split("-", 1L);
auto addrRange = addr.split("-", 1L); auto addrRange = addr.split("-", 1L);
uint bankLo = hex(bankRange(0)); uint bankLo = bankRange(0).hex();
uint bankHi = hex(bankRange(1, bankRange(0))); uint bankHi = bankRange(1, bankRange(0)).hex();
uint addrLo = hex(addrRange(0)); uint addrLo = addrRange(0).hex();
uint addrHi = hex(addrRange(1, addrRange(0))); uint addrHi = addrRange(1, addrRange(0)).hex();
for(uint bank = bankLo; bank <= bankHi; bank++) { for(uint bank = bankLo; bank <= bankHi; bank++) {
for(uint addr = addrLo; addr <= addrHi; addr++) { for(uint addr = addrLo; addr <= addrHi; addr++) {
@ -79,10 +78,10 @@ auto Bus::unmap(const string& addr) -> void {
for(auto& addr : addrs) { for(auto& addr : addrs) {
auto bankRange = bank.split("-", 1L); auto bankRange = bank.split("-", 1L);
auto addrRange = addr.split("-", 1L); auto addrRange = addr.split("-", 1L);
uint bankLo = hex(bankRange(0)); uint bankLo = bankRange(0).hex();
uint bankHi = hex(bankRange(1, bankRange(0))); uint bankHi = bankRange(1, bankRange(0)).hex();
uint addrLo = hex(addrRange(0)); uint addrLo = addrRange(0).hex();
uint addrHi = hex(addrRange(1, addrRange(1))); uint addrHi = addrRange(1, addrRange(1)).hex();
for(uint bank = bankLo; bank <= bankHi; bank++) { for(uint bank = bankLo; bank <= bankHi; bank++) {
for(uint addr = addrLo; addr <= addrHi; addr++) { for(uint addr = addrLo; addr <= addrHi; addr++) {

View File

@ -1,13 +1,13 @@
#include "mode7.cpp" #include "mode7.cpp"
auto PPU::Background::voffset() const -> uint16 { auto PPU::Background::voffset() const -> uint16 {
if(r.mosaic) return latch.voffset; if(io.mosaic) return latch.voffset;
return r.voffset; return io.voffset;
} }
auto PPU::Background::hoffset() const -> uint16 { auto PPU::Background::hoffset() const -> uint16 {
if(r.mosaic) return latch.hoffset; if(io.mosaic) return latch.hoffset;
return r.hoffset; return io.hoffset;
} }
//V = 0, H = 0 //V = 0, H = 0
@ -20,70 +20,70 @@ auto PPU::Background::scanline() -> void {
//H = 28 //H = 28
auto PPU::Background::begin() -> void { auto PPU::Background::begin() -> void {
bool hires = (ppu.r.bgMode == 5 || ppu.r.bgMode == 6); bool hires = (ppu.io.bgMode == 5 || ppu.io.bgMode == 6);
x = -7; x = -7;
y = ppu.vcounter(); y = ppu.vcounter();
if(y == 1) { if(y == 1) {
mosaic.vcounter = r.mosaic + 1; mosaic.vcounter = io.mosaic + 1;
mosaic.voffset = 1; mosaic.voffset = 1;
latch.hoffset = r.hoffset; latch.hoffset = io.hoffset;
latch.voffset = r.voffset; latch.voffset = io.voffset;
} else if(--mosaic.vcounter == 0) { } else if(--mosaic.vcounter == 0) {
mosaic.vcounter = r.mosaic + 1; mosaic.vcounter = io.mosaic + 1;
mosaic.voffset += r.mosaic + 1; mosaic.voffset += io.mosaic + 1;
latch.hoffset = r.hoffset; latch.hoffset = io.hoffset;
latch.voffset = r.voffset; latch.voffset = io.voffset;
} }
tileCounter = (7 - (latch.hoffset & 7)) << hires; tileCounter = (7 - (latch.hoffset & 7)) << hires;
for(auto& d : data) d = 0; for(auto& d : data) d = 0;
mosaic.hcounter = r.mosaic + 1; mosaic.hcounter = io.mosaic + 1;
mosaic.hoffset = 0; mosaic.hoffset = 0;
if(r.mode == Mode::Mode7) return beginMode7(); if(io.mode == Mode::Mode7) return beginMode7();
if(r.mosaic == 0) { if(io.mosaic == 0) {
latch.hoffset = r.hoffset; latch.hoffset = io.hoffset;
latch.voffset = r.voffset; latch.voffset = io.voffset;
} }
} }
auto PPU::Background::getTile() -> void { auto PPU::Background::getTile() -> void {
bool hires = (ppu.r.bgMode == 5 || ppu.r.bgMode == 6); bool hires = (ppu.io.bgMode == 5 || ppu.io.bgMode == 6);
uint colorDepth = (r.mode == Mode::BPP2 ? 0 : r.mode == Mode::BPP4 ? 1 : 2); uint colorDepth = (io.mode == Mode::BPP2 ? 0 : io.mode == Mode::BPP4 ? 1 : 2);
uint paletteOffset = (ppu.r.bgMode == 0 ? id << 5 : 0); uint paletteOffset = (ppu.io.bgMode == 0 ? id << 5 : 0);
uint paletteSize = 2 << colorDepth; uint paletteSize = 2 << colorDepth;
uint tileMask = ppu.vram.mask >> (3 + colorDepth); uint tileMask = ppu.vram.mask >> (3 + colorDepth);
uint tiledataIndex = r.tiledataAddress >> (3 + colorDepth); uint tiledataIndex = io.tiledataAddress >> (3 + colorDepth);
uint tileHeight = (r.tileSize == TileSize::Size8x8 ? 3 : 4); uint tileHeight = (io.tileSize == TileSize::Size8x8 ? 3 : 4);
uint tileWidth = (!hires ? tileHeight : 4); uint tileWidth = (!hires ? tileHeight : 4);
uint width = 256 << hires; uint width = 256 << hires;
uint hmask = (tileHeight == 3 ? width : width << 1); uint hmask = (tileHeight == 3 ? width : width << 1);
uint vmask = hmask; uint vmask = hmask;
if(r.screenSize & 1) hmask <<= 1; if(io.screenSize & 1) hmask <<= 1;
if(r.screenSize & 2) vmask <<= 1; if(io.screenSize & 2) vmask <<= 1;
hmask--; hmask--;
vmask--; vmask--;
uint px = x << hires; uint px = x << hires;
uint py = (r.mosaic == 0 ? y : mosaic.voffset); uint py = (io.mosaic == 0 ? y : mosaic.voffset);
uint hscroll = hoffset(); uint hscroll = hoffset();
uint vscroll = voffset(); uint vscroll = voffset();
if(hires) { if(hires) {
hscroll <<= 1; hscroll <<= 1;
if(ppu.r.interlace) py = (py << 1) + ppu.field(); if(ppu.io.interlace) py = (py << 1) + ppu.field();
} }
uint hoffset = hscroll + px; uint hoffset = hscroll + px;
uint voffset = vscroll + py; uint voffset = vscroll + py;
if(ppu.r.bgMode == 2 || ppu.r.bgMode == 4 || ppu.r.bgMode == 6) { if(ppu.io.bgMode == 2 || ppu.io.bgMode == 4 || ppu.io.bgMode == 6) {
uint16 offsetX = (x + (hscroll & 7)); uint16 offsetX = (x + (hscroll & 7));
if(offsetX >= 8) { if(offsetX >= 8) {
@ -91,7 +91,7 @@ auto PPU::Background::getTile() -> void {
uint vval = ppu.bg3.getTile((offsetX - 8) + (ppu.bg3.hoffset() & ~7), ppu.bg3.voffset() + 8); uint vval = ppu.bg3.getTile((offsetX - 8) + (ppu.bg3.hoffset() & ~7), ppu.bg3.voffset() + 8);
uint validMask = (id == ID::BG1 ? 0x2000 : 0x4000); uint validMask = (id == ID::BG1 ? 0x2000 : 0x4000);
if(ppu.r.bgMode == 4) { if(ppu.io.bgMode == 4) {
if(hval & validMask) { if(hval & validMask) {
if((hval & 0x8000) == 0) { if((hval & 0x8000) == 0) {
hoffset = offsetX + (hval & ~7); hoffset = offsetX + (hval & ~7);
@ -109,9 +109,9 @@ auto PPU::Background::getTile() -> void {
hoffset &= hmask; hoffset &= hmask;
voffset &= vmask; voffset &= vmask;
uint screenX = (r.screenSize & 1 ? 32 << 5 : 0); uint screenX = (io.screenSize & 1 ? 32 << 5 : 0);
uint screenY = (r.screenSize & 2 ? 32 << 5 : 0); uint screenY = (io.screenSize & 2 ? 32 << 5 : 0);
if(r.screenSize == 3) screenY <<= 1; if(io.screenSize == 3) screenY <<= 1;
uint tx = hoffset >> tileWidth; uint tx = hoffset >> tileWidth;
uint ty = voffset >> tileHeight; uint ty = voffset >> tileHeight;
@ -120,11 +120,11 @@ auto PPU::Background::getTile() -> void {
if(tx & 0x20) offset += screenX; if(tx & 0x20) offset += screenX;
if(ty & 0x20) offset += screenY; if(ty & 0x20) offset += screenY;
uint16 address = r.screenAddress + offset; uint16 address = io.screenAddress + offset;
tile = ppu.vram[address]; tile = ppu.vram[address];
bool mirrorY = tile & 0x8000; bool mirrorY = tile & 0x8000;
bool mirrorX = tile & 0x4000; bool mirrorX = tile & 0x4000;
priority = r.priority[bool(tile & 0x2000)]; priority = io.priority[bool(tile & 0x2000)];
paletteNumber = (tile >> 10) & 7; paletteNumber = (tile >> 10) & 7;
paletteIndex = paletteOffset + (paletteNumber << paletteSize); paletteIndex = paletteOffset + (paletteNumber << paletteSize);
@ -135,7 +135,7 @@ auto PPU::Background::getTile() -> void {
if(mirrorY) voffset ^= 7; if(mirrorY) voffset ^= 7;
offset = (character << (3 + colorDepth)) + (voffset & 7); offset = (character << (3 + colorDepth)) + (voffset & 7);
switch(r.mode) { switch(io.mode) {
case Mode::BPP8: case Mode::BPP8:
data[1].bits(16,31) = ppu.vram[offset + 24]; data[1].bits(16,31) = ppu.vram[offset + 24];
data[1].bits( 0,15) = ppu.vram[offset + 16]; data[1].bits( 0,15) = ppu.vram[offset + 16];
@ -154,7 +154,7 @@ auto PPU::Background::getTile() -> void {
auto PPU::Background::run(bool screen) -> void { auto PPU::Background::run(bool screen) -> void {
if(ppu.vcounter() == 0) return; if(ppu.vcounter() == 0) return;
bool hires = (ppu.r.bgMode == 5 || ppu.r.bgMode == 6); bool hires = (ppu.io.bgMode == 5 || ppu.io.bgMode == 6);
if(screen == Screen::Below) { if(screen == Screen::Below) {
output.above.priority = 0; output.above.priority = 0;
@ -167,12 +167,12 @@ auto PPU::Background::run(bool screen) -> void {
getTile(); getTile();
} }
if(r.mode == Mode::Mode7) return runMode7(); if(io.mode == Mode::Mode7) return runMode7();
uint8 palette = getTileColor(); uint8 palette = getTileColor();
if(x == 0) mosaic.hcounter = 1; if(x == 0) mosaic.hcounter = 1;
if(x >= 0 && --mosaic.hcounter == 0) { if(x >= 0 && --mosaic.hcounter == 0) {
mosaic.hcounter = r.mosaic + 1; mosaic.hcounter = io.mosaic + 1;
mosaic.priority = priority; mosaic.priority = priority;
mosaic.palette = palette ? paletteIndex + palette : 0; mosaic.palette = palette ? paletteIndex + palette : 0;
mosaic.tile = tile; mosaic.tile = tile;
@ -180,14 +180,14 @@ auto PPU::Background::run(bool screen) -> void {
if(screen == Screen::Above) x++; if(screen == Screen::Above) x++;
if(mosaic.palette == 0) return; if(mosaic.palette == 0) return;
if(!hires || screen == Screen::Above) if(r.aboveEnable) output.above = mosaic; if(!hires || screen == Screen::Above) if(io.aboveEnable) output.above = mosaic;
if(!hires || screen == Screen::Below) if(r.belowEnable) output.below = mosaic; if(!hires || screen == Screen::Below) if(io.belowEnable) output.below = mosaic;
} }
auto PPU::Background::getTileColor() -> uint { auto PPU::Background::getTileColor() -> uint {
uint color = 0; uint color = 0;
switch(r.mode) { switch(io.mode) {
case Mode::BPP8: case Mode::BPP8:
color += data[1] >> 24 & 0x80; color += data[1] >> 24 & 0x80;
color += data[1] >> 17 & 0x40; color += data[1] >> 17 & 0x40;
@ -207,17 +207,17 @@ auto PPU::Background::getTileColor() -> uint {
} }
auto PPU::Background::reset() -> void { auto PPU::Background::reset() -> void {
r.tiledataAddress = (random(0x0000) & 0x0f) << 12; io.tiledataAddress = (random(0x0000) & 0x0f) << 12;
r.screenAddress = (random(0x0000) & 0xfc) << 8; io.screenAddress = (random(0x0000) & 0xfc) << 8;
r.screenSize = random(0); io.screenSize = random(0);
r.mosaic = random(0); io.mosaic = random(0);
r.tileSize = random(0); io.tileSize = random(0);
r.mode = 0; io.mode = 0;
for(auto& p : r.priority) p = 0; for(auto& p : io.priority) p = 0;
r.aboveEnable = random(0); io.aboveEnable = random(0);
r.belowEnable = random(0); io.belowEnable = random(0);
r.hoffset = random(0x0000); io.hoffset = random(0x0000);
r.voffset = random(0x0000); io.voffset = random(0x0000);
latch.hoffset = 0; latch.hoffset = 0;
latch.voffset = 0; latch.voffset = 0;
@ -248,20 +248,20 @@ auto PPU::Background::reset() -> void {
} }
auto PPU::Background::getTile(uint x, uint y) -> uint { auto PPU::Background::getTile(uint x, uint y) -> uint {
bool hires = (ppu.r.bgMode == 5 || ppu.r.bgMode == 6); bool hires = (ppu.io.bgMode == 5 || ppu.io.bgMode == 6);
uint tileHeight = (r.tileSize == TileSize::Size8x8 ? 3 : 4); uint tileHeight = (io.tileSize == TileSize::Size8x8 ? 3 : 4);
uint tileWidth = (!hires ? tileHeight : 4); uint tileWidth = (!hires ? tileHeight : 4);
uint width = (!hires ? 256 : 512); uint width = (!hires ? 256 : 512);
uint maskX = (tileHeight == 3 ? width : width << 1); uint maskX = (tileHeight == 3 ? width : width << 1);
uint maskY = maskX; uint maskY = maskX;
if(r.screenSize & 1) maskX <<= 1; if(io.screenSize & 1) maskX <<= 1;
if(r.screenSize & 2) maskY <<= 1; if(io.screenSize & 2) maskY <<= 1;
maskX--; maskX--;
maskY--; maskY--;
uint screenX = (r.screenSize & 1 ? 32 << 5 : 0); uint screenX = (io.screenSize & 1 ? 32 << 5 : 0);
uint screenY = (r.screenSize & 2 ? 32 << 5 : 0); uint screenY = (io.screenSize & 2 ? 32 << 5 : 0);
if(r.screenSize == 3) screenY <<= 1; if(io.screenSize == 3) screenY <<= 1;
x = (x & maskX) >> tileWidth; x = (x & maskX) >> tileWidth;
y = (y & maskY) >> tileHeight; y = (y & maskY) >> tileHeight;
@ -270,6 +270,6 @@ auto PPU::Background::getTile(uint x, uint y) -> uint {
if(x & 0x20) offset += screenX; if(x & 0x20) offset += screenX;
if(y & 0x20) offset += screenY; if(y & 0x20) offset += screenY;
uint16 address = r.screenAddress + offset; uint16 address = io.screenAddress + offset;
return ppu.vram[address]; return ppu.vram[address];
} }

View File

@ -27,7 +27,7 @@ struct Background {
struct TileSize { enum : uint { Size8x8, Size16x16 }; }; struct TileSize { enum : uint { Size8x8, Size16x16 }; };
struct Screen { enum : uint { Above, Below }; }; struct Screen { enum : uint { Above, Below }; };
struct Registers { struct IO {
uint16 tiledataAddress; uint16 tiledataAddress;
uint16 screenAddress; uint16 screenAddress;
uint2 screenSize; uint2 screenSize;
@ -42,7 +42,7 @@ struct Background {
uint16 hoffset; uint16 hoffset;
uint16 voffset; uint16 voffset;
} r; } io;
struct Latch { struct Latch {
uint16 hoffset; uint16 hoffset;

View File

@ -5,18 +5,18 @@ auto PPU::Background::clip(int n) -> int {
//H = 28 //H = 28
auto PPU::Background::beginMode7() -> void { auto PPU::Background::beginMode7() -> void {
latch.hoffset = ppu.r.hoffsetMode7; latch.hoffset = ppu.io.hoffsetMode7;
latch.voffset = ppu.r.voffsetMode7; latch.voffset = ppu.io.voffsetMode7;
} }
auto PPU::Background::runMode7() -> void { auto PPU::Background::runMode7() -> void {
int a = (int16)ppu.r.m7a; int a = (int16)ppu.io.m7a;
int b = (int16)ppu.r.m7b; int b = (int16)ppu.io.m7b;
int c = (int16)ppu.r.m7c; int c = (int16)ppu.io.m7c;
int d = (int16)ppu.r.m7d; int d = (int16)ppu.io.m7d;
int cx = (int13)ppu.r.m7x; int cx = (int13)ppu.io.m7x;
int cy = (int13)ppu.r.m7y; int cy = (int13)ppu.io.m7y;
int hoffset = (int13)latch.hoffset; int hoffset = (int13)latch.hoffset;
int voffset = (int13)latch.voffset; int voffset = (int13)latch.voffset;
@ -25,12 +25,12 @@ auto PPU::Background::runMode7() -> void {
uint y = ppu.bg1.mosaic.voffset; //BG2 vertical mosaic uses BG1 mosaic size uint y = ppu.bg1.mosaic.voffset; //BG2 vertical mosaic uses BG1 mosaic size
if(--mosaic.hcounter == 0) { if(--mosaic.hcounter == 0) {
mosaic.hcounter = r.mosaic + 1; mosaic.hcounter = io.mosaic + 1;
mosaic.hoffset += r.mosaic + 1; mosaic.hoffset += io.mosaic + 1;
} }
if(ppu.r.hflipMode7) x = 255 - x; if(ppu.io.hflipMode7) x = 255 - x;
if(ppu.r.vflipMode7) y = 255 - y; if(ppu.io.vflipMode7) y = 255 - y;
int psx = ((a * clip(hoffset - cx)) & ~63) + ((b * clip(voffset - cy)) & ~63) + ((b * y) & ~63) + (cx << 8); int psx = ((a * clip(hoffset - cx)) & ~63) + ((b * clip(voffset - cy)) & ~63) + ((b * y) & ~63) + (cx << 8);
int psy = ((c * clip(hoffset - cx)) & ~63) + ((d * clip(voffset - cy)) & ~63) + ((d * y) & ~63) + (cy << 8); int psy = ((c * clip(hoffset - cx)) & ~63) + ((d * clip(voffset - cy)) & ~63) + ((d * y) & ~63) + (cy << 8);
@ -44,7 +44,7 @@ auto PPU::Background::runMode7() -> void {
uint tile; uint tile;
uint palette; uint palette;
switch(ppu.r.repeatMode7) { switch(ppu.io.repeatMode7) {
//screen repetition outside of screen area //screen repetition outside of screen area
case 0: case 0:
case 1: case 1:
@ -81,21 +81,21 @@ auto PPU::Background::runMode7() -> void {
uint priority; uint priority;
if(id == ID::BG1) { if(id == ID::BG1) {
priority = r.priority[0]; priority = io.priority[0];
} else if(id == ID::BG2) { } else if(id == ID::BG2) {
priority = r.priority[bool(palette & 0x80)]; priority = io.priority[bool(palette & 0x80)];
palette &= 0x7f; palette &= 0x7f;
} }
if(palette == 0) return; if(palette == 0) return;
if(r.aboveEnable) { if(io.aboveEnable) {
output.above.palette = palette; output.above.palette = palette;
output.above.priority = priority; output.above.priority = priority;
output.above.tile = 0; output.above.tile = 0;
} }
if(r.belowEnable) { if(io.belowEnable) {
output.below.palette = palette; output.below.palette = palette;
output.below.priority = priority; output.below.priority = priority;
output.below.tile = 0; output.below.tile = 0;

View File

@ -1,6 +1,6 @@
auto PPU::getVramAddress() -> uint16 { auto PPU::getVramAddress() -> uint16 {
uint16 address = r.vramAddress; uint16 address = io.vramAddress;
switch(r.vramMapping) { switch(io.vramMapping) {
case 0: return (address); case 0: return (address);
case 1: return (address & 0xff00) | ((address & 0x001f) << 3) | ((address >> 5) & 7); case 1: return (address & 0xff00) | ((address & 0x001f) << 3) | ((address >> 5) & 7);
case 2: return (address & 0xfe00) | ((address & 0x003f) << 3) | ((address >> 6) & 7); case 2: return (address & 0xfe00) | ((address & 0x003f) << 3) | ((address >> 6) & 7);
@ -10,12 +10,11 @@ auto PPU::getVramAddress() -> uint16 {
} }
auto PPU::vramAccessible() const -> bool { auto PPU::vramAccessible() const -> bool {
return r.displayDisable || vcounter() >= vdisp(); return io.displayDisable || vcounter() >= vdisp();
} }
auto PPU::oamWrite(uint addr, uint8 data) -> void { auto PPU::oamWrite(uint addr, uint8 data) -> void {
oam[addr] = data; obj.oam.write(addr, data);
obj.update(addr, data);
} }
auto PPU::readIO(uint24 addr, uint8 data) -> uint8 { auto PPU::readIO(uint24 addr, uint8 data) -> uint8 {
@ -33,21 +32,21 @@ auto PPU::readIO(uint24 addr, uint8 data) -> uint8 {
//MPYL //MPYL
case 0x2134: { case 0x2134: {
uint result = (int16)r.m7a * (int8)(r.m7b >> 8); uint result = (int16)io.m7a * (int8)(io.m7b >> 8);
ppu1.mdr = (result >> 0); ppu1.mdr = (result >> 0);
return ppu1.mdr; return ppu1.mdr;
} }
//MPYM //MPYM
case 0x2135: { case 0x2135: {
uint result = (int16)r.m7a * (int8)(r.m7b >> 8); uint result = (int16)io.m7a * (int8)(io.m7b >> 8);
ppu1.mdr = (result >> 8); ppu1.mdr = (result >> 8);
return ppu1.mdr; return ppu1.mdr;
} }
//MPYH //MPYH
case 0x2136: { case 0x2136: {
uint result = (int16)r.m7a * (int8)(r.m7b >> 8); uint result = (int16)io.m7a * (int8)(io.m7b >> 8);
ppu1.mdr = (result >> 16); ppu1.mdr = (result >> 16);
return ppu1.mdr; return ppu1.mdr;
} }
@ -55,16 +54,16 @@ auto PPU::readIO(uint24 addr, uint8 data) -> uint8 {
//SLHV //SLHV
case 0x2137: { case 0x2137: {
if(cpu.pio() & 0x80) latchCounters(); if(cpu.pio() & 0x80) latchCounters();
return cpu.r.mdr; return data; //CPU MDR
} }
//OAMDATAREAD //OAMDATAREAD
case 0x2138: { case 0x2138: {
uint10 address = r.oamAddress++; uint10 address = io.oamAddress++;
if(!r.displayDisable && vcounter() < vdisp()) address = latch.oamAddress; if(!io.displayDisable && vcounter() < vdisp()) address = latch.oamAddress;
if(address & 0x0200) address &= 0x021f; if(address & 0x0200) address &= 0x021f;
ppu1.mdr = oam[address]; ppu1.mdr = obj.oam.read(address);
obj.setFirstSprite(); obj.setFirstSprite();
return ppu1.mdr; return ppu1.mdr;
} }
@ -72,9 +71,9 @@ auto PPU::readIO(uint24 addr, uint8 data) -> uint8 {
//VMDATALREAD //VMDATALREAD
case 0x2139: { case 0x2139: {
ppu1.mdr = latch.vram >> 0; ppu1.mdr = latch.vram >> 0;
if(r.vramIncrementMode == 0) { if(io.vramIncrementMode == 0) {
latch.vram = vramAccessible() ? vram[getVramAddress()] : (uint16)0; latch.vram = vramAccessible() ? vram[getVramAddress()] : (uint16)0;
r.vramAddress += r.vramIncrementSize; io.vramAddress += io.vramIncrementSize;
} }
return ppu1.mdr; return ppu1.mdr;
} }
@ -82,26 +81,26 @@ auto PPU::readIO(uint24 addr, uint8 data) -> uint8 {
//VMDATAHREAD //VMDATAHREAD
case 0x213a: { case 0x213a: {
ppu1.mdr = latch.vram >> 8; ppu1.mdr = latch.vram >> 8;
if(r.vramIncrementMode == 1) { if(io.vramIncrementMode == 1) {
latch.vram = vramAccessible() ? vram[getVramAddress()] : (uint16)0; latch.vram = vramAccessible() ? vram[getVramAddress()] : (uint16)0;
r.vramAddress += r.vramIncrementSize; io.vramAddress += io.vramIncrementSize;
} }
return ppu1.mdr; return ppu1.mdr;
} }
//CGDATAREAD //CGDATAREAD
case 0x213b: { case 0x213b: {
auto address = r.cgramAddress; auto address = io.cgramAddress;
if(!r.displayDisable if(!io.displayDisable
&& vcounter() > 0 && vcounter() < vdisp() && vcounter() > 0 && vcounter() < vdisp()
&& hcounter() >= 88 && hcounter() < 1096 && hcounter() >= 88 && hcounter() < 1096
) address = latch.cgramAddress; ) address = latch.cgramAddress;
if(r.cgramAddressLatch++) { if(io.cgramAddressLatch++) {
ppu2.mdr = cgram[address].byte(0); ppu2.mdr = screen.cgram[address].byte(0);
} else { } else {
ppu2.mdr &= 0x80; ppu2.mdr &= 0x80;
ppu2.mdr |= cgram[address].byte(1); ppu2.mdr |= screen.cgram[address].byte(1);
} }
return ppu2.mdr; return ppu2.mdr;
} }
@ -109,10 +108,10 @@ auto PPU::readIO(uint24 addr, uint8 data) -> uint8 {
//OPHCT //OPHCT
case 0x213c: { case 0x213c: {
if(latch.hcounter == 0) { if(latch.hcounter == 0) {
ppu2.mdr = (r.hcounter >> 0); ppu2.mdr = (io.hcounter >> 0);
} else { } else {
ppu2.mdr &= 0xfe; ppu2.mdr &= 0xfe;
ppu2.mdr |= (r.hcounter >> 8) & 1; ppu2.mdr |= (io.hcounter >> 8) & 1;
} }
latch.hcounter ^= 1; latch.hcounter ^= 1;
return ppu2.mdr; return ppu2.mdr;
@ -121,10 +120,10 @@ auto PPU::readIO(uint24 addr, uint8 data) -> uint8 {
//OPVCT //OPVCT
case 0x213d: { case 0x213d: {
if(latch.vcounter == 0) { if(latch.vcounter == 0) {
ppu2.mdr = (r.vcounter >> 0); ppu2.mdr = (io.vcounter >> 0);
} else { } else {
ppu2.mdr &= 0xfe; ppu2.mdr &= 0xfe;
ppu2.mdr |= (r.vcounter >> 8) & 1; ppu2.mdr |= (io.vcounter >> 8) & 1;
} }
latch.vcounter ^= 1; latch.vcounter ^= 1;
return ppu2.mdr; return ppu2.mdr;
@ -133,8 +132,8 @@ auto PPU::readIO(uint24 addr, uint8 data) -> uint8 {
//STAT77 //STAT77
case 0x213e: { case 0x213e: {
ppu1.mdr &= 0x10; ppu1.mdr &= 0x10;
ppu1.mdr |= obj.r.timeOver << 7; ppu1.mdr |= obj.io.timeOver << 7;
ppu1.mdr |= obj.r.rangeOver << 6; ppu1.mdr |= obj.io.rangeOver << 6;
ppu1.mdr |= ppu1.version & 0x0f; ppu1.mdr |= ppu1.version & 0x0f;
return ppu1.mdr; return ppu1.mdr;
} }
@ -169,40 +168,40 @@ auto PPU::writeIO(uint24 addr, uint8 data) -> void {
//INIDISP //INIDISP
case 0x2100: { case 0x2100: {
if(r.displayDisable && vcounter() == vdisp()) obj.addressReset(); if(io.displayDisable && vcounter() == vdisp()) obj.addressReset();
r.displayBrightness = data.bits(0,3); io.displayBrightness = data.bits(0,3);
r.displayDisable = data.bit (7); io.displayDisable = data.bit (7);
return; return;
} }
//OBSEL //OBSEL
case 0x2101: { case 0x2101: {
obj.r.tiledataAddress = data.bits(0,2) << 13; obj.io.tiledataAddress = data.bits(0,2) << 13;
obj.r.nameSelect = data.bits(3,4); obj.io.nameselect = data.bits(3,4);
obj.r.baseSize = data.bits(5,7); obj.io.baseSize = data.bits(5,7);
return; return;
} }
//OAMADDL //OAMADDL
case 0x2102: { case 0x2102: {
r.oamBaseAddress = (r.oamBaseAddress & 0x0200) | (data << 1); io.oamBaseAddress = (io.oamBaseAddress & 0x0200) | (data << 1);
obj.addressReset(); obj.addressReset();
return; return;
} }
//OAMADDH //OAMADDH
case 0x2103: { case 0x2103: {
r.oamPriority = data & 0x80; io.oamPriority = data & 0x80;
r.oamBaseAddress = ((data & 0x01) << 9) | (r.oamBaseAddress & 0x01fe); io.oamBaseAddress = ((data & 0x01) << 9) | (io.oamBaseAddress & 0x01fe);
obj.addressReset(); obj.addressReset();
return; return;
} }
//OAMDATA //OAMDATA
case 0x2104: { case 0x2104: {
bool l = r.oamAddress & 1; bool l = io.oamAddress & 1;
uint10 address = r.oamAddress++; uint10 address = io.oamAddress++;
if(!r.displayDisable && vcounter() < vdisp()) address = latch.oamAddress; if(!io.displayDisable && vcounter() < vdisp()) address = latch.oamAddress;
if(address & 0x0200) address &= 0x021f; if(address & 0x0200) address &= 0x021f;
if(l == 0) latch.oam = data; if(l == 0) latch.oam = data;
@ -218,12 +217,12 @@ auto PPU::writeIO(uint24 addr, uint8 data) -> void {
//BGMODE //BGMODE
case 0x2105: { case 0x2105: {
r.bgMode = data.bits(0,2); io.bgMode = data.bits(0,2);
r.bgPriority = data.bit (3); io.bgPriority = data.bit (3);
bg1.r.tileSize = data.bit (4); bg1.io.tileSize = data.bit (4);
bg2.r.tileSize = data.bit (5); bg2.io.tileSize = data.bit (5);
bg3.r.tileSize = data.bit (6); bg3.io.tileSize = data.bit (6);
bg4.r.tileSize = data.bit (7); bg4.io.tileSize = data.bit (7);
updateVideoMode(); updateVideoMode();
return; return;
} }
@ -231,140 +230,136 @@ auto PPU::writeIO(uint24 addr, uint8 data) -> void {
//MOSAIC //MOSAIC
case 0x2106: { case 0x2106: {
uint mosaicSize = data.bits(4,7); uint mosaicSize = data.bits(4,7);
bg1.r.mosaic = data.bit(0) ? mosaicSize : 0; bg1.io.mosaic = data.bit(0) ? mosaicSize : 0;
bg2.r.mosaic = data.bit(1) ? mosaicSize : 0; bg2.io.mosaic = data.bit(1) ? mosaicSize : 0;
bg3.r.mosaic = data.bit(2) ? mosaicSize : 0; bg3.io.mosaic = data.bit(2) ? mosaicSize : 0;
bg4.r.mosaic = data.bit(3) ? mosaicSize : 0; bg4.io.mosaic = data.bit(3) ? mosaicSize : 0;
return; return;
} }
//BG1SC //BG1SC
case 0x2107: { case 0x2107: {
bg1.r.screenSize = data.bits(0,1); bg1.io.screenSize = data.bits(0,1);
bg1.r.screenAddress = data.bits(2,7) << 10; bg1.io.screenAddress = data.bits(2,7) << 10;
return; return;
} }
//BG2SC //BG2SC
case 0x2108: { case 0x2108: {
bg2.r.screenSize = data.bits(0,1); bg2.io.screenSize = data.bits(0,1);
bg2.r.screenAddress = data.bits(2,7) << 10; bg2.io.screenAddress = data.bits(2,7) << 10;
return; return;
} }
//BG3SC //BG3SC
case 0x2109: { case 0x2109: {
bg3.r.screenSize = data.bits(0,1); bg3.io.screenSize = data.bits(0,1);
bg3.r.screenAddress = data.bits(2,7) << 10; bg3.io.screenAddress = data.bits(2,7) << 10;
return; return;
} }
//BG4SC //BG4SC
case 0x210a: { case 0x210a: {
bg4.r.screenSize = data.bits(0,1); bg4.io.screenSize = data.bits(0,1);
bg4.r.screenAddress = data.bits(2,7) << 10; bg4.io.screenAddress = data.bits(2,7) << 10;
return; return;
} }
//BG12NBA //BG12NBA
case 0x210b: { case 0x210b: {
bg1.r.tiledataAddress = data.bits(0,3) << 12; bg1.io.tiledataAddress = data.bits(0,3) << 12;
bg2.r.tiledataAddress = data.bits(4,7) << 12; bg2.io.tiledataAddress = data.bits(4,7) << 12;
return; return;
} }
//BG34NBA //BG34NBA
case 0x210c: { case 0x210c: {
bg3.r.tiledataAddress = data.bits(0,3) << 12; bg3.io.tiledataAddress = data.bits(0,3) << 12;
bg4.r.tiledataAddress = data.bits(4,7) << 12; bg4.io.tiledataAddress = data.bits(4,7) << 12;
return; return;
} }
//BG1HOFS //BG1HOFS
case 0x210d: { case 0x210d: {
r.hoffsetMode7 = (data << 8) | latch.mode7; io.hoffsetMode7 = (data << 8) | latch.mode7;
latch.mode7 = data; latch.mode7 = data;
bg1.r.hoffset = (data << 8) | (latch.bgofs & ~7) | ((bg1.r.hoffset >> 8) & 7); bg1.io.hoffset = (data << 8) | (latch.bgofs & ~7) | ((bg1.io.hoffset >> 8) & 7);
latch.bgofs = data; latch.bgofs = data;
return; return;
} }
//BG1VOFS //BG1VOFS
case 0x210e: { case 0x210e: {
r.voffsetMode7 = (data << 8) | latch.mode7; io.voffsetMode7 = (data << 8) | latch.mode7;
latch.mode7 = data; latch.mode7 = data;
bg1.r.voffset = (data << 8) | latch.bgofs; bg1.io.voffset = (data << 8) | latch.bgofs;
latch.bgofs = data; latch.bgofs = data;
return; return;
} }
//BG2HOFS //BG2HOFS
case 0x210f: { case 0x210f: {
bg2.r.hoffset = (data << 8) | (latch.bgofs & ~7) | ((bg2.r.hoffset >> 8) & 7); bg2.io.hoffset = (data << 8) | (latch.bgofs & ~7) | ((bg2.io.hoffset >> 8) & 7);
latch.bgofs = data; latch.bgofs = data;
return; return;
} }
//BG2VOFS //BG2VOFS
case 0x2110: { case 0x2110: {
bg2.r.voffset = (data << 8) | latch.bgofs; bg2.io.voffset = (data << 8) | latch.bgofs;
latch.bgofs = data; latch.bgofs = data;
return; return;
} }
//BG3HOFS //BG3HOFS
case 0x2111: { case 0x2111: {
bg3.r.hoffset = (data << 8) | (latch.bgofs & ~7) | ((bg3.r.hoffset >> 8) & 7); bg3.io.hoffset = (data << 8) | (latch.bgofs & ~7) | ((bg3.io.hoffset >> 8) & 7);
latch.bgofs = data; latch.bgofs = data;
return; return;
} }
//BG3VOFS //BG3VOFS
case 0x2112: { case 0x2112: {
bg3.r.voffset = (data << 8) | latch.bgofs; bg3.io.voffset = (data << 8) | latch.bgofs;
latch.bgofs = data; latch.bgofs = data;
return; return;
} }
//BG4HOFS //BG4HOFS
case 0x2113: { case 0x2113: {
bg4.r.hoffset = (data << 8) | (latch.bgofs & ~7) | ((bg4.r.hoffset >> 8) & 7); bg4.io.hoffset = (data << 8) | (latch.bgofs & ~7) | ((bg4.io.hoffset >> 8) & 7);
latch.bgofs = data; latch.bgofs = data;
return; return;
} }
//BG4VOFS //BG4VOFS
case 0x2114: { case 0x2114: {
bg4.r.voffset = (data << 8) | latch.bgofs; bg4.io.voffset = (data << 8) | latch.bgofs;
latch.bgofs = data; latch.bgofs = data;
return; return;
} }
//VMAIN //VMAIN
case 0x2115: { case 0x2115: {
r.vramIncrementMode = data & 0x80; static const uint size[4] = {1, 32, 128, 128};
r.vramMapping = (data >> 2) & 3; io.vramIncrementSize = size[data.bits(0,1)];
switch(data & 3) { io.vramMapping = data.bits(2,3);
case 0: r.vramIncrementSize = 1; break; io.vramIncrementMode = data.bit (7);
case 1: r.vramIncrementSize = 32; break;
case 2: r.vramIncrementSize = 128; break;
case 3: r.vramIncrementSize = 128; break;
}
return; return;
} }
//VMADDL //VMADDL
case 0x2116: { case 0x2116: {
r.vramAddress.byte(0) = data; io.vramAddress.byte(0) = data;
latch.vram = vramAccessible() ? vram[getVramAddress()] : (uint16)0; latch.vram = vramAccessible() ? vram[getVramAddress()] : (uint16)0;
return; return;
} }
//VMADDH //VMADDH
case 0x2117: { case 0x2117: {
r.vramAddress.byte(1) = data; io.vramAddress.byte(1) = data;
latch.vram = vramAccessible() ? vram[getVramAddress()] : (uint16)0; latch.vram = vramAccessible() ? vram[getVramAddress()] : (uint16)0;
return; return;
} }
@ -372,247 +367,247 @@ auto PPU::writeIO(uint24 addr, uint8 data) -> void {
//VMDATAL //VMDATAL
case 0x2118: { case 0x2118: {
if(vramAccessible()) vram[getVramAddress()].byte(0) = data; if(vramAccessible()) vram[getVramAddress()].byte(0) = data;
if(r.vramIncrementMode == 0) r.vramAddress += r.vramIncrementSize; if(io.vramIncrementMode == 0) io.vramAddress += io.vramIncrementSize;
return; return;
} }
//VMDATAH //VMDATAH
case 0x2119: { case 0x2119: {
if(vramAccessible()) vram[getVramAddress()].byte(1) = data; if(vramAccessible()) vram[getVramAddress()].byte(1) = data;
if(r.vramIncrementMode == 1) r.vramAddress += r.vramIncrementSize; if(io.vramIncrementMode == 1) io.vramAddress += io.vramIncrementSize;
return; return;
} }
//M7SEL //M7SEL
case 0x211a: { case 0x211a: {
r.hflipMode7 = data.bit (0); io.hflipMode7 = data.bit (0);
r.vflipMode7 = data.bit (1); io.vflipMode7 = data.bit (1);
r.repeatMode7 = data.bits(6,7); io.repeatMode7 = data.bits(6,7);
return; return;
} }
//M7A //M7A
case 0x211b: { case 0x211b: {
r.m7a = data << 8 | latch.mode7; io.m7a = data << 8 | latch.mode7;
latch.mode7 = data; latch.mode7 = data;
return; return;
} }
//M7B //M7B
case 0x211c: { case 0x211c: {
r.m7b = data << 8 | latch.mode7; io.m7b = data << 8 | latch.mode7;
latch.mode7 = data; latch.mode7 = data;
return; return;
} }
//M7C //M7C
case 0x211d: { case 0x211d: {
r.m7c = data << 8 | latch.mode7; io.m7c = data << 8 | latch.mode7;
latch.mode7 = data; latch.mode7 = data;
return; return;
} }
//M7D //M7D
case 0x211e: { case 0x211e: {
r.m7d = data << 8 | latch.mode7; io.m7d = data << 8 | latch.mode7;
latch.mode7 = data; latch.mode7 = data;
return; return;
} }
//M7X //M7X
case 0x211f: { case 0x211f: {
r.m7x = data << 8 | latch.mode7; io.m7x = data << 8 | latch.mode7;
latch.mode7 = data; latch.mode7 = data;
return; return;
} }
//M7Y //M7Y
case 0x2120: { case 0x2120: {
r.m7y = data << 8 | latch.mode7; io.m7y = data << 8 | latch.mode7;
latch.mode7 = data; latch.mode7 = data;
return; return;
} }
//CGADD //CGADD
case 0x2121: { case 0x2121: {
r.cgramAddress = data; io.cgramAddress = data;
r.cgramAddressLatch = 0; io.cgramAddressLatch = 0;
return; return;
} }
//CGDATA //CGDATA
case 0x2122: { case 0x2122: {
auto address = r.cgramAddress; auto address = io.cgramAddress;
if(!r.displayDisable if(!io.displayDisable
&& vcounter() > 0 && vcounter() < vdisp() && vcounter() > 0 && vcounter() < vdisp()
&& hcounter() >= 88 && hcounter() < 1096 && hcounter() >= 88 && hcounter() < 1096
) address = latch.cgramAddress; ) address = latch.cgramAddress;
if(r.cgramAddressLatch++ == 0) { if(io.cgramAddressLatch++ == 0) {
latch.cgram = data; latch.cgram = data;
} else { } else {
cgram[address] = data.bits(0,6) << 8 | latch.cgram; screen.cgram[address] = data.bits(0,6) << 8 | latch.cgram;
r.cgramAddress++; io.cgramAddress++;
} }
return; return;
} }
//W12SEL //W12SEL
case 0x2123: { case 0x2123: {
window.r.bg1.oneInvert = data.bit(0); window.io.bg1.oneInvert = data.bit(0);
window.r.bg1.oneEnable = data.bit(1); window.io.bg1.oneEnable = data.bit(1);
window.r.bg1.twoInvert = data.bit(2); window.io.bg1.twoInvert = data.bit(2);
window.r.bg1.twoEnable = data.bit(3); window.io.bg1.twoEnable = data.bit(3);
window.r.bg2.oneInvert = data.bit(4); window.io.bg2.oneInvert = data.bit(4);
window.r.bg2.oneEnable = data.bit(5); window.io.bg2.oneEnable = data.bit(5);
window.r.bg2.twoInvert = data.bit(6); window.io.bg2.twoInvert = data.bit(6);
window.r.bg2.twoEnable = data.bit(7); window.io.bg2.twoEnable = data.bit(7);
return; return;
} }
//W34SEL //W34SEL
case 0x2124: { case 0x2124: {
window.r.bg3.oneInvert = data.bit(0); window.io.bg3.oneInvert = data.bit(0);
window.r.bg3.oneEnable = data.bit(1); window.io.bg3.oneEnable = data.bit(1);
window.r.bg3.twoInvert = data.bit(2); window.io.bg3.twoInvert = data.bit(2);
window.r.bg3.twoEnable = data.bit(3); window.io.bg3.twoEnable = data.bit(3);
window.r.bg4.oneInvert = data.bit(4); window.io.bg4.oneInvert = data.bit(4);
window.r.bg4.oneEnable = data.bit(5); window.io.bg4.oneEnable = data.bit(5);
window.r.bg4.twoInvert = data.bit(6); window.io.bg4.twoInvert = data.bit(6);
window.r.bg4.twoEnable = data.bit(7); window.io.bg4.twoEnable = data.bit(7);
return; return;
} }
//WOBJSEL //WOBJSEL
case 0x2125: { case 0x2125: {
window.r.obj.oneInvert = data.bit(0); window.io.obj.oneInvert = data.bit(0);
window.r.obj.oneEnable = data.bit(1); window.io.obj.oneEnable = data.bit(1);
window.r.obj.twoInvert = data.bit(2); window.io.obj.twoInvert = data.bit(2);
window.r.obj.twoEnable = data.bit(3); window.io.obj.twoEnable = data.bit(3);
window.r.col.oneInvert = data.bit(4); window.io.col.oneInvert = data.bit(4);
window.r.col.oneEnable = data.bit(5); window.io.col.oneEnable = data.bit(5);
window.r.col.twoInvert = data.bit(6); window.io.col.twoInvert = data.bit(6);
window.r.col.twoEnable = data.bit(7); window.io.col.twoEnable = data.bit(7);
return; return;
} }
//WH0 //WH0
case 0x2126: { case 0x2126: {
window.r.oneLeft = data; window.io.oneLeft = data;
return; return;
} }
//WH1 //WH1
case 0x2127: { case 0x2127: {
window.r.oneRight = data; window.io.oneRight = data;
return; return;
} }
//WH2 //WH2
case 0x2128: { case 0x2128: {
window.r.twoLeft = data; window.io.twoLeft = data;
return; return;
} }
//WH3 //WH3
case 0x2129: { case 0x2129: {
window.r.twoRight = data; window.io.twoRight = data;
return; return;
} }
//WBGLOG //WBGLOG
case 0x212a: { case 0x212a: {
window.r.bg1.mask = data.bits(0,1); window.io.bg1.mask = data.bits(0,1);
window.r.bg2.mask = data.bits(2,3); window.io.bg2.mask = data.bits(2,3);
window.r.bg3.mask = data.bits(4,5); window.io.bg3.mask = data.bits(4,5);
window.r.bg4.mask = data.bits(6,7); window.io.bg4.mask = data.bits(6,7);
return; return;
} }
//WOBJLOG //WOBJLOG
case 0x212b: { case 0x212b: {
window.r.obj.mask = data.bits(0,1); window.io.obj.mask = data.bits(0,1);
window.r.col.mask = data.bits(2,3); window.io.col.mask = data.bits(2,3);
return; return;
} }
//TM //TM
case 0x212c: { case 0x212c: {
bg1.r.aboveEnable = data.bit(0); bg1.io.aboveEnable = data.bit(0);
bg2.r.aboveEnable = data.bit(1); bg2.io.aboveEnable = data.bit(1);
bg3.r.aboveEnable = data.bit(2); bg3.io.aboveEnable = data.bit(2);
bg4.r.aboveEnable = data.bit(3); bg4.io.aboveEnable = data.bit(3);
obj.r.aboveEnable = data.bit(4); obj.io.aboveEnable = data.bit(4);
return; return;
} }
//TS //TS
case 0x212d: { case 0x212d: {
bg1.r.belowEnable = data.bit(0); bg1.io.belowEnable = data.bit(0);
bg2.r.belowEnable = data.bit(1); bg2.io.belowEnable = data.bit(1);
bg3.r.belowEnable = data.bit(2); bg3.io.belowEnable = data.bit(2);
bg4.r.belowEnable = data.bit(3); bg4.io.belowEnable = data.bit(3);
obj.r.belowEnable = data.bit(4); obj.io.belowEnable = data.bit(4);
return; return;
} }
//TMW //TMW
case 0x212e: { case 0x212e: {
window.r.bg1.aboveEnable = data.bit(0); window.io.bg1.aboveEnable = data.bit(0);
window.r.bg2.aboveEnable = data.bit(1); window.io.bg2.aboveEnable = data.bit(1);
window.r.bg3.aboveEnable = data.bit(2); window.io.bg3.aboveEnable = data.bit(2);
window.r.bg4.aboveEnable = data.bit(3); window.io.bg4.aboveEnable = data.bit(3);
window.r.obj.aboveEnable = data.bit(4); window.io.obj.aboveEnable = data.bit(4);
return; return;
} }
//TSW //TSW
case 0x212f: { case 0x212f: {
window.r.bg1.belowEnable = data.bit(0); window.io.bg1.belowEnable = data.bit(0);
window.r.bg2.belowEnable = data.bit(1); window.io.bg2.belowEnable = data.bit(1);
window.r.bg3.belowEnable = data.bit(2); window.io.bg3.belowEnable = data.bit(2);
window.r.bg4.belowEnable = data.bit(3); window.io.bg4.belowEnable = data.bit(3);
window.r.obj.belowEnable = data.bit(4); window.io.obj.belowEnable = data.bit(4);
return; return;
} }
//CGWSEL //CGWSEL
case 0x2130: { case 0x2130: {
screen.r.directColor = data.bit (0); screen.io.directColor = data.bit (0);
screen.r.blendMode = data.bit (1); screen.io.blendMode = data.bit (1);
window.r.col.belowMask = data.bits(4,5); window.io.col.belowMask = data.bits(4,5);
window.r.col.aboveMask = data.bits(6,7); window.io.col.aboveMask = data.bits(6,7);
return; return;
} }
//CGADDSUB //CGADDSUB
case 0x2131: { case 0x2131: {
screen.r.bg1.colorEnable = data.bit(0); screen.io.bg1.colorEnable = data.bit(0);
screen.r.bg2.colorEnable = data.bit(1); screen.io.bg2.colorEnable = data.bit(1);
screen.r.bg3.colorEnable = data.bit(2); screen.io.bg3.colorEnable = data.bit(2);
screen.r.bg4.colorEnable = data.bit(3); screen.io.bg4.colorEnable = data.bit(3);
screen.r.obj.colorEnable = data.bit(4); screen.io.obj.colorEnable = data.bit(4);
screen.r.back.colorEnable = data.bit(5); screen.io.back.colorEnable = data.bit(5);
screen.r.colorHalve = data.bit(6); screen.io.colorHalve = data.bit(6);
screen.r.colorMode = data.bit(7); screen.io.colorMode = data.bit(7);
return; return;
} }
//COLDATA //COLDATA
case 0x2132: { case 0x2132: {
if(data.bit(5)) screen.r.colorRed = data.bits(0,4); if(data.bit(5)) screen.io.colorRed = data.bits(0,4);
if(data.bit(6)) screen.r.colorGreen = data.bits(0,4); if(data.bit(6)) screen.io.colorGreen = data.bits(0,4);
if(data.bit(7)) screen.r.colorBlue = data.bits(0,4); if(data.bit(7)) screen.io.colorBlue = data.bits(0,4);
return; return;
} }
//SETINI //SETINI
case 0x2133: { case 0x2133: {
r.interlace = data.bit(0); io.interlace = data.bit(0);
obj.r.interlace = data.bit(1); obj.io.interlace = data.bit(1);
r.overscan = data.bit(2); io.overscan = data.bit(2);
r.pseudoHires = data.bit(3); io.pseudoHires = data.bit(3);
r.extbg = data.bit(6); io.extbg = data.bit(6);
updateVideoMode(); updateVideoMode();
return; return;
} }
@ -622,108 +617,108 @@ auto PPU::writeIO(uint24 addr, uint8 data) -> void {
auto PPU::latchCounters() -> void { auto PPU::latchCounters() -> void {
cpu.synchronizePPU(); cpu.synchronizePPU();
r.hcounter = hdot(); io.hcounter = hdot();
r.vcounter = vcounter(); io.vcounter = vcounter();
latch.counters = true; latch.counters = true;
} }
auto PPU::updateVideoMode() -> void { auto PPU::updateVideoMode() -> void {
switch(r.bgMode) { switch(io.bgMode) {
case 0: case 0:
bg1.r.mode = Background::Mode::BPP2; bg1.io.mode = Background::Mode::BPP2;
bg2.r.mode = Background::Mode::BPP2; bg2.io.mode = Background::Mode::BPP2;
bg3.r.mode = Background::Mode::BPP2; bg3.io.mode = Background::Mode::BPP2;
bg4.r.mode = Background::Mode::BPP2; bg4.io.mode = Background::Mode::BPP2;
memory::assign(bg1.r.priority, 8, 11); memory::assign(bg1.io.priority, 8, 11);
memory::assign(bg2.r.priority, 7, 10); memory::assign(bg2.io.priority, 7, 10);
memory::assign(bg3.r.priority, 2, 5); memory::assign(bg3.io.priority, 2, 5);
memory::assign(bg4.r.priority, 1, 4); memory::assign(bg4.io.priority, 1, 4);
memory::assign(obj.r.priority, 3, 6, 9, 12); memory::assign(obj.io.priority, 3, 6, 9, 12);
break; break;
case 1: case 1:
bg1.r.mode = Background::Mode::BPP4; bg1.io.mode = Background::Mode::BPP4;
bg2.r.mode = Background::Mode::BPP4; bg2.io.mode = Background::Mode::BPP4;
bg3.r.mode = Background::Mode::BPP2; bg3.io.mode = Background::Mode::BPP2;
bg4.r.mode = Background::Mode::Inactive; bg4.io.mode = Background::Mode::Inactive;
if(r.bgPriority) { if(io.bgPriority) {
memory::assign(bg1.r.priority, 5, 8); memory::assign(bg1.io.priority, 5, 8);
memory::assign(bg2.r.priority, 4, 7); memory::assign(bg2.io.priority, 4, 7);
memory::assign(bg3.r.priority, 1, 10); memory::assign(bg3.io.priority, 1, 10);
memory::assign(obj.r.priority, 2, 3, 6, 9); memory::assign(obj.io.priority, 2, 3, 6, 9);
} else { } else {
memory::assign(bg1.r.priority, 6, 9); memory::assign(bg1.io.priority, 6, 9);
memory::assign(bg2.r.priority, 5, 8); memory::assign(bg2.io.priority, 5, 8);
memory::assign(bg3.r.priority, 1, 3); memory::assign(bg3.io.priority, 1, 3);
memory::assign(obj.r.priority, 2, 4, 7, 10); memory::assign(obj.io.priority, 2, 4, 7, 10);
} }
break; break;
case 2: case 2:
bg1.r.mode = Background::Mode::BPP4; bg1.io.mode = Background::Mode::BPP4;
bg2.r.mode = Background::Mode::BPP4; bg2.io.mode = Background::Mode::BPP4;
bg3.r.mode = Background::Mode::Inactive; bg3.io.mode = Background::Mode::Inactive;
bg4.r.mode = Background::Mode::Inactive; bg4.io.mode = Background::Mode::Inactive;
memory::assign(bg1.r.priority, 3, 7); memory::assign(bg1.io.priority, 3, 7);
memory::assign(bg2.r.priority, 1, 5); memory::assign(bg2.io.priority, 1, 5);
memory::assign(obj.r.priority, 2, 4, 6, 8); memory::assign(obj.io.priority, 2, 4, 6, 8);
break; break;
case 3: case 3:
bg1.r.mode = Background::Mode::BPP8; bg1.io.mode = Background::Mode::BPP8;
bg2.r.mode = Background::Mode::BPP4; bg2.io.mode = Background::Mode::BPP4;
bg3.r.mode = Background::Mode::Inactive; bg3.io.mode = Background::Mode::Inactive;
bg4.r.mode = Background::Mode::Inactive; bg4.io.mode = Background::Mode::Inactive;
memory::assign(bg1.r.priority, 3, 7); memory::assign(bg1.io.priority, 3, 7);
memory::assign(bg2.r.priority, 1, 5); memory::assign(bg2.io.priority, 1, 5);
memory::assign(obj.r.priority, 2, 4, 6, 8); memory::assign(obj.io.priority, 2, 4, 6, 8);
break; break;
case 4: case 4:
bg1.r.mode = Background::Mode::BPP8; bg1.io.mode = Background::Mode::BPP8;
bg2.r.mode = Background::Mode::BPP2; bg2.io.mode = Background::Mode::BPP2;
bg3.r.mode = Background::Mode::Inactive; bg3.io.mode = Background::Mode::Inactive;
bg4.r.mode = Background::Mode::Inactive; bg4.io.mode = Background::Mode::Inactive;
memory::assign(bg1.r.priority, 3, 7); memory::assign(bg1.io.priority, 3, 7);
memory::assign(bg2.r.priority, 1, 5); memory::assign(bg2.io.priority, 1, 5);
memory::assign(obj.r.priority, 2, 4, 6, 8); memory::assign(obj.io.priority, 2, 4, 6, 8);
break; break;
case 5: case 5:
bg1.r.mode = Background::Mode::BPP4; bg1.io.mode = Background::Mode::BPP4;
bg2.r.mode = Background::Mode::BPP2; bg2.io.mode = Background::Mode::BPP2;
bg3.r.mode = Background::Mode::Inactive; bg3.io.mode = Background::Mode::Inactive;
bg4.r.mode = Background::Mode::Inactive; bg4.io.mode = Background::Mode::Inactive;
memory::assign(bg1.r.priority, 3, 7); memory::assign(bg1.io.priority, 3, 7);
memory::assign(bg2.r.priority, 1, 5); memory::assign(bg2.io.priority, 1, 5);
memory::assign(obj.r.priority, 2, 4, 6, 8); memory::assign(obj.io.priority, 2, 4, 6, 8);
break; break;
case 6: case 6:
bg1.r.mode = Background::Mode::BPP4; bg1.io.mode = Background::Mode::BPP4;
bg2.r.mode = Background::Mode::Inactive; bg2.io.mode = Background::Mode::Inactive;
bg3.r.mode = Background::Mode::Inactive; bg3.io.mode = Background::Mode::Inactive;
bg4.r.mode = Background::Mode::Inactive; bg4.io.mode = Background::Mode::Inactive;
memory::assign(bg1.r.priority, 2, 5); memory::assign(bg1.io.priority, 2, 5);
memory::assign(obj.r.priority, 1, 3, 4, 6); memory::assign(obj.io.priority, 1, 3, 4, 6);
break; break;
case 7: case 7:
if(!r.extbg) { if(!io.extbg) {
bg1.r.mode = Background::Mode::Mode7; bg1.io.mode = Background::Mode::Mode7;
bg2.r.mode = Background::Mode::Inactive; bg2.io.mode = Background::Mode::Inactive;
bg3.r.mode = Background::Mode::Inactive; bg3.io.mode = Background::Mode::Inactive;
bg4.r.mode = Background::Mode::Inactive; bg4.io.mode = Background::Mode::Inactive;
memory::assign(bg1.r.priority, 2); memory::assign(bg1.io.priority, 2);
memory::assign(obj.r.priority, 1, 3, 4, 5); memory::assign(obj.io.priority, 1, 3, 4, 5);
} else { } else {
bg1.r.mode = Background::Mode::Mode7; bg1.io.mode = Background::Mode::Mode7;
bg2.r.mode = Background::Mode::Mode7; bg2.io.mode = Background::Mode::Mode7;
bg3.r.mode = Background::Mode::Inactive; bg3.io.mode = Background::Mode::Inactive;
bg4.r.mode = Background::Mode::Inactive; bg4.io.mode = Background::Mode::Inactive;
memory::assign(bg1.r.priority, 3); memory::assign(bg1.io.priority, 3);
memory::assign(bg2.r.priority, 1, 5); memory::assign(bg2.io.priority, 1, 5);
memory::assign(obj.r.priority, 2, 4, 6, 7); memory::assign(obj.io.priority, 2, 4, 6, 7);
} }
break; break;
} }

View File

@ -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];
}
}

View File

@ -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];
}
}

View File

@ -1,17 +1,17 @@
#include "list.cpp" #include "oam.cpp"
auto PPU::Object::addressReset() -> void { auto PPU::Object::addressReset() -> void {
ppu.r.oamAddress = ppu.r.oamBaseAddress; ppu.io.oamAddress = ppu.io.oamBaseAddress;
setFirstSprite(); setFirstSprite();
} }
auto PPU::Object::setFirstSprite() -> void { auto PPU::Object::setFirstSprite() -> void {
r.firstSprite = !ppu.r.oamPriority ? 0 : ppu.r.oamAddress >> 2; io.firstSprite = !ppu.io.oamPriority ? 0 : ppu.io.oamAddress >> 2;
} }
auto PPU::Object::frame() -> void { auto PPU::Object::frame() -> void {
r.timeOver = false; io.timeOver = false;
r.rangeOver = false; io.rangeOver = false;
} }
auto PPU::Object::scanline() -> void { auto PPU::Object::scanline() -> void {
@ -25,15 +25,15 @@ auto PPU::Object::scanline() -> void {
auto oamItem = t.item[t.active]; auto oamItem = t.item[t.active];
auto oamTile = t.tile[t.active]; auto oamTile = t.tile[t.active];
if(t.y == ppu.vdisp() && !ppu.r.displayDisable) addressReset(); if(t.y == ppu.vdisp() && !ppu.io.displayDisable) addressReset();
if(t.y >= ppu.vdisp() - 1) return; if(t.y >= ppu.vdisp() - 1) return;
for(auto n : range(32)) oamItem[n].valid = false; //default to invalid for(auto n : range(32)) oamItem[n].valid = false; //default to invalid
for(auto n : range(34)) oamTile[n].valid = false; //default to invalid for(auto n : range(34)) oamTile[n].valid = false; //default to invalid
for(auto n : range(128)) { for(auto n : range(128)) {
uint7 sprite = r.firstSprite + n; uint7 sprite = io.firstSprite + n;
if(!onScanline(list[sprite])) continue; if(!onScanline(oam.object[sprite])) continue;
if(t.itemCount++ >= 32) break; if(t.itemCount++ >= 32) break;
oamItem[t.itemCount - 1] = {true, sprite}; oamItem[t.itemCount - 1] = {true, sprite};
} }
@ -43,9 +43,9 @@ auto PPU::Object::scanline() -> void {
} }
} }
auto PPU::Object::onScanline(Sprite& sprite) -> bool { auto PPU::Object::onScanline(PPU::OAM::Object& sprite) -> bool {
if(sprite.x > 256 && (sprite.x + sprite.width() - 1) < 512) return false; if(sprite.x > 256 && (sprite.x + sprite.width() - 1) < 512) return false;
int height = sprite.height() >> r.interlace; int height = sprite.height() >> io.interlace;
if(t.y >= sprite.y && t.y < (sprite.y + height)) return true; if(t.y >= sprite.y && t.y < (sprite.y + height)) return true;
if((sprite.y + height) >= 256 && t.y < ((sprite.y + height) & 255)) return true; if((sprite.y + height) >= 256 && t.y < ((sprite.y + height) & 255)) return true;
return false; return false;
@ -72,14 +72,14 @@ auto PPU::Object::run() -> void {
color += tile.data >> (shift + 21) & 8; color += tile.data >> (shift + 21) & 8;
if(color) { if(color) {
if(r.aboveEnable) { if(io.aboveEnable) {
output.above.palette = tile.palette + color; output.above.palette = tile.palette + color;
output.above.priority = r.priority[tile.priority]; output.above.priority = io.priority[tile.priority];
} }
if(r.belowEnable) { if(io.belowEnable) {
output.below.palette = tile.palette + color; output.below.palette = tile.palette + color;
output.below.priority = r.priority[tile.priority]; output.below.priority = io.priority[tile.priority];
} }
} }
} }
@ -91,12 +91,12 @@ auto PPU::Object::tilefetch() -> void {
for(int i = 31; i >= 0; i--) { for(int i = 31; i >= 0; i--) {
if(!oamItem[i].valid) continue; if(!oamItem[i].valid) continue;
const auto& sprite = list[oamItem[i].index]; const auto& sprite = oam.object[oamItem[i].index];
uint tileWidth = sprite.width() >> 3; uint tileWidth = sprite.width() >> 3;
int x = sprite.x; int x = sprite.x;
int y = (t.y - sprite.y) & 0xff; int y = (t.y - sprite.y) & 0xff;
if(r.interlace) y <<= 1; if(io.interlace) y <<= 1;
if(sprite.vflip) { if(sprite.vflip) {
if(sprite.width() == sprite.height()) { if(sprite.width() == sprite.height()) {
@ -108,18 +108,18 @@ auto PPU::Object::tilefetch() -> void {
} }
} }
if(r.interlace) { if(io.interlace) {
y = !sprite.vflip ? y + ppu.field() : y - ppu.field(); y = !sprite.vflip ? y + ppu.field() : y - ppu.field();
} }
x &= 511; x &= 511;
y &= 255; y &= 255;
uint16 tiledataAddress = r.tiledataAddress; uint16 tiledataAddress = io.tiledataAddress;
uint16 chrx = (sprite.character >> 0) & 15; uint16 chrx = (sprite.character >> 0) & 15;
uint16 chry = (sprite.character >> 4) & 15; uint16 chry = (sprite.character >> 4) & 15;
if(sprite.nameSelect) { if(sprite.nameselect) {
tiledataAddress += (256 * 16) + (r.nameSelect << 12); tiledataAddress += (256 * 16) + (io.nameselect << 12);
} }
chry += (y >> 3); chry += (y >> 3);
chry &= 15; chry &= 15;
@ -142,31 +142,30 @@ auto PPU::Object::tilefetch() -> void {
uint16 addr = (pos & 0xfff0) + (y & 7); uint16 addr = (pos & 0xfff0) + (y & 7);
oamTile[n].data.bits( 0,15) = ppu.vram[addr + 0]; oamTile[n].data.bits( 0,15) = ppu.vram[addr + 0];
ppu.addClocks(2); ppu.step(2);
oamTile[n].data.bits(16,31) = ppu.vram[addr + 8]; oamTile[n].data.bits(16,31) = ppu.vram[addr + 8];
ppu.addClocks(2); ppu.step(2);
} }
} }
if(t.tileCount < 34) ppu.addClocks((34 - t.tileCount) * 4); if(t.tileCount < 34) ppu.step((34 - t.tileCount) * 4);
r.timeOver |= (t.tileCount > 34); io.timeOver |= (t.tileCount > 34);
r.rangeOver |= (t.itemCount > 32); io.rangeOver |= (t.itemCount > 32);
} }
auto PPU::Object::reset() -> void { auto PPU::Object::reset() -> void {
for(auto n : range(128)) { for(auto& object : oam.object) {
list[n].x = 0; object.x = 0;
list[n].y = 0; object.y = 0;
list[n].character = 0; object.character = 0;
list[n].nameSelect = 0; object.nameselect = 0;
list[n].vflip = 0; object.vflip = 0;
list[n].hflip = 0; object.hflip = 0;
list[n].priority = 0; object.priority = 0;
list[n].palette = 0; object.palette = 0;
list[n].size = 0; object.size = 0;
} }
synchronize();
t.x = 0; t.x = 0;
t.y = 0; t.y = 0;
@ -190,19 +189,19 @@ auto PPU::Object::reset() -> void {
} }
} }
r.aboveEnable = random(false); io.aboveEnable = random(false);
r.belowEnable = random(false); io.belowEnable = random(false);
r.interlace = random(false); io.interlace = random(false);
r.baseSize = random(0); io.baseSize = random(0);
r.nameSelect = random(0); io.nameselect = random(0);
r.tiledataAddress = (random(0x0000) & 3) << 13; io.tiledataAddress = (random(0x0000) & 7) << 13;
r.firstSprite = 0; io.firstSprite = 0;
for(auto& p : r.priority) p = 0; for(auto& p : io.priority) p = 0;
r.timeOver = false; io.timeOver = false;
r.rangeOver = false; io.rangeOver = false;
output.above.palette = 0; output.above.palette = 0;
output.above.priority = 0; output.above.priority = 0;

View File

@ -1,3 +1,23 @@
struct OAM {
auto read(uint10 addr) -> uint8;
auto write(uint10 addr, uint8 data) -> void;
struct Object {
alwaysinline auto width() const -> uint;
alwaysinline auto height() const -> uint;
uint9 x;
uint8 y;
uint8 character;
uint1 nameselect;
uint1 vflip;
uint1 hflip;
uint2 priority;
uint3 palette;
uint1 size;
} object[128];
};
struct Object { struct Object {
alwaysinline auto addressReset() -> void; alwaysinline auto addressReset() -> void;
alwaysinline auto setFirstSprite() -> void; alwaysinline auto setFirstSprite() -> void;
@ -7,22 +27,19 @@ struct Object {
auto tilefetch() -> void; auto tilefetch() -> void;
auto reset() -> void; auto reset() -> void;
struct Sprite; auto onScanline(PPU::OAM::Object&) -> bool;
auto onScanline(Sprite&) -> bool;
//list.cpp
auto update(uint10 addr, uint8 data) -> void;
auto synchronize() -> void;
auto serialize(serializer&) -> void; auto serialize(serializer&) -> void;
struct Registers { OAM oam;
struct IO {
bool aboveEnable; bool aboveEnable;
bool belowEnable; bool belowEnable;
bool interlace; bool interlace;
uint3 baseSize; uint3 baseSize;
uint2 nameSelect; uint2 nameselect;
uint16 tiledataAddress; uint16 tiledataAddress;
uint7 firstSprite; uint7 firstSprite;
@ -30,7 +47,7 @@ struct Object {
bool timeOver; bool timeOver;
bool rangeOver; bool rangeOver;
} r; } io;
struct Item { struct Item {
bool valid; bool valid;
@ -65,20 +82,5 @@ struct Object {
} above, below; } above, below;
} output; } output;
struct Sprite {
alwaysinline auto width() const -> uint;
alwaysinline auto height() const -> uint;
uint9 x;
uint8 y;
uint8 character;
uint1 nameSelect;
uint1 vflip;
uint1 hflip;
uint2 priority;
uint3 palette;
uint1 size;
} list[128];
friend class PPU; friend class PPU;
}; };

View File

@ -29,7 +29,12 @@ PPU::~PPU() {
} }
auto PPU::step(uint clocks) -> void { auto PPU::step(uint clocks) -> void {
clock += clocks; clocks >>= 1;
while(clocks--) {
tick(2);
clock += 2;
synchronizeCPU();
}
} }
auto PPU::synchronizeCPU() -> void { auto PPU::synchronizeCPU() -> void {
@ -42,7 +47,7 @@ auto PPU::Enter() -> void {
auto PPU::main() -> void { auto PPU::main() -> void {
scanline(); scanline();
addClocks(28); step(28);
bg1.begin(); bg1.begin();
bg2.begin(); bg2.begin();
bg3.begin(); bg3.begin();
@ -54,7 +59,7 @@ auto PPU::main() -> void {
bg2.run(1); bg2.run(1);
bg3.run(1); bg3.run(1);
bg4.run(1); bg4.run(1);
addClocks(2); step(2);
bg1.run(0); bg1.run(0);
bg2.run(0); bg2.run(0);
@ -65,25 +70,16 @@ auto PPU::main() -> void {
window.run(); window.run();
screen.run(); screen.run();
} }
addClocks(2); step(2);
} }
addClocks(14); step(14);
obj.tilefetch(); obj.tilefetch();
} else { } else {
addClocks(1052 + 14 + 136); step(1052 + 14 + 136);
} }
addClocks(lineclocks() - 28 - 1052 - 14 - 136); step(lineclocks() - 28 - 1052 - 14 - 136);
}
auto PPU::addClocks(uint clocks) -> void {
clocks >>= 1;
while(clocks--) {
tick(2);
step(2);
synchronizeCPU();
}
} }
auto PPU::load(Markup::Node node) -> bool { auto PPU::load(Markup::Node node) -> bool {
@ -96,8 +92,6 @@ auto PPU::load(Markup::Node node) -> bool {
auto PPU::power() -> void { auto PPU::power() -> void {
for(auto& n : vram.data) n = random(0x0000); for(auto& n : vram.data) n = random(0x0000);
for(auto& n : oam.data) n = random(0x00);
for(auto& n : cgram.data) n = random(0x0000);
} }
auto PPU::reset() -> void { auto PPU::reset() -> void {
@ -125,72 +119,72 @@ auto PPU::reset() -> void {
latch.cgramAddress = 0x00; latch.cgramAddress = 0x00;
//$2100 INIDISP //$2100 INIDISP
r.displayDisable = true; io.displayDisable = true;
r.displayBrightness = 0; io.displayBrightness = 0;
//$2102 OAMADDL //$2102 OAMADDL
//$2103 OAMADDH //$2103 OAMADDH
r.oamBaseAddress = random(0x0000); io.oamBaseAddress = random(0x0000);
r.oamAddress = random(0x0000); io.oamAddress = random(0x0000);
r.oamPriority = random(false); io.oamPriority = random(false);
//$2105 BGMODE //$2105 BGMODE
r.bgPriority = false; io.bgPriority = false;
r.bgMode = 0; io.bgMode = 0;
//$210d BG1HOFS //$210d BG1HOFS
r.hoffsetMode7 = random(0x0000); io.hoffsetMode7 = random(0x0000);
//$210e BG1VOFS //$210e BG1VOFS
r.voffsetMode7 = random(0x0000); io.voffsetMode7 = random(0x0000);
//$2115 VMAIN //$2115 VMAIN
r.vramIncrementMode = random(1); io.vramIncrementMode = random(1);
r.vramMapping = random(0); io.vramMapping = random(0);
r.vramIncrementSize = 1; io.vramIncrementSize = 1;
//$2116 VMADDL //$2116 VMADDL
//$2117 VMADDH //$2117 VMADDH
r.vramAddress = random(0x0000); io.vramAddress = random(0x0000);
//$211a M7SEL //$211a M7SEL
r.repeatMode7 = random(0); io.repeatMode7 = random(0);
r.vflipMode7 = random(false); io.vflipMode7 = random(false);
r.hflipMode7 = random(false); io.hflipMode7 = random(false);
//$211b M7A //$211b M7A
r.m7a = random(0x0000); io.m7a = random(0x0000);
//$211c M7B //$211c M7B
r.m7b = random(0x0000); io.m7b = random(0x0000);
//$211d M7C //$211d M7C
r.m7c = random(0x0000); io.m7c = random(0x0000);
//$211e M7D //$211e M7D
r.m7d = random(0x0000); io.m7d = random(0x0000);
//$211f M7X //$211f M7X
r.m7x = random(0x0000); io.m7x = random(0x0000);
//$2120 M7Y //$2120 M7Y
r.m7y = random(0x0000); io.m7y = random(0x0000);
//$2121 CGADD //$2121 CGADD
r.cgramAddress = random(0x00); io.cgramAddress = random(0x00);
r.cgramAddressLatch = random(0); io.cgramAddressLatch = random(0);
//$2133 SETINI //$2133 SETINI
r.extbg = random(false); io.extbg = random(false);
r.pseudoHires = random(false); io.pseudoHires = random(false);
r.overscan = false; io.overscan = false;
r.interlace = false; io.interlace = false;
//$213c OPHCT //$213c OPHCT
r.hcounter = 0; io.hcounter = 0;
//$213d OPVCT //$213d OPVCT
r.vcounter = 0; io.vcounter = 0;
bg1.reset(); bg1.reset();
bg2.reset(); bg2.reset();
@ -227,8 +221,8 @@ auto PPU::scanline() -> void {
auto PPU::frame() -> void { auto PPU::frame() -> void {
obj.frame(); obj.frame();
display.interlace = r.interlace; display.interlace = io.interlace;
display.overscan = r.overscan; display.overscan = io.overscan;
} }
auto PPU::refresh() -> void { auto PPU::refresh() -> void {

View File

@ -1,7 +1,7 @@
struct PPU : Thread, PPUcounter { struct PPU : Thread, PPUcounter {
alwaysinline auto interlace() const -> bool { return display.interlace; } alwaysinline auto interlace() const -> bool { return display.interlace; }
alwaysinline auto overscan() const -> bool { return display.overscan; } alwaysinline auto overscan() const -> bool { return display.overscan; }
alwaysinline auto vdisp() const -> uint { return r.overscan ? 240 : 225; } alwaysinline auto vdisp() const -> uint { return io.overscan ? 240 : 225; }
PPU(); PPU();
~PPU(); ~PPU();
@ -33,16 +33,6 @@ privileged:
uint mask = 0x7fff; uint mask = 0x7fff;
} vram; } vram;
struct OAM {
auto& operator[](uint offset) { return data[offset]; }
uint8 data[544];
} oam;
struct CGRAM {
auto& operator[](uint8 offset) { return data[offset]; }
uint15 data[256];
} cgram;
uint32* output = nullptr; uint32* output = nullptr;
struct { struct {
@ -50,8 +40,6 @@ privileged:
bool overscan; bool overscan;
} display; } display;
alwaysinline auto addClocks(uint) -> void;
auto scanline() -> void; auto scanline() -> void;
auto frame() -> void; auto frame() -> void;
auto refresh() -> void; auto refresh() -> void;
@ -75,7 +63,7 @@ privileged:
uint8 cgramAddress; uint8 cgramAddress;
} latch; } latch;
struct Registers { struct IO {
//$2100 INIDISP //$2100 INIDISP
bool displayDisable; bool displayDisable;
uint4 displayBrightness; uint4 displayBrightness;
@ -143,7 +131,7 @@ privileged:
//$213d OPVCT //$213d OPVCT
uint16 vcounter; uint16 vcounter;
} r; } io;
#include "background/background.hpp" #include "background/background.hpp"
#include "object/object.hpp" #include "object/object.hpp"

View File

@ -8,32 +8,32 @@ auto PPU::Screen::scanline() -> void {
math.above.color = paletteColor(0); math.above.color = paletteColor(0);
math.below.color = math.above.color; math.below.color = math.above.color;
math.above.colorEnable = !(ppu.window.r.col.aboveMask & 1); math.above.colorEnable = !(ppu.window.io.col.aboveMask & 1);
math.below.colorEnable = !(ppu.window.r.col.belowMask & 1) && r.back.colorEnable; math.below.colorEnable = !(ppu.window.io.col.belowMask & 1) && io.back.colorEnable;
math.transparent = true; math.transparent = true;
math.blendMode = false; math.blendMode = false;
math.colorHalve = r.colorHalve && !r.blendMode && math.above.colorEnable; math.colorHalve = io.colorHalve && !io.blendMode && math.above.colorEnable;
} }
auto PPU::Screen::run() -> void { auto PPU::Screen::run() -> void {
if(ppu.vcounter() == 0) return; if(ppu.vcounter() == 0) return;
bool hires = ppu.r.pseudoHires || ppu.r.bgMode == 5 || ppu.r.bgMode == 6; bool hires = ppu.io.pseudoHires || ppu.io.bgMode == 5 || ppu.io.bgMode == 6;
auto belowColor = below(hires); auto belowColor = below(hires);
auto aboveColor = above(); auto aboveColor = above();
*lineA++ = *lineB++ = ppu.r.displayBrightness << 15 | (hires ? belowColor : aboveColor); *lineA++ = *lineB++ = ppu.io.displayBrightness << 15 | (hires ? belowColor : aboveColor);
*lineA++ = *lineB++ = ppu.r.displayBrightness << 15 | (aboveColor); *lineA++ = *lineB++ = ppu.io.displayBrightness << 15 | (aboveColor);
} }
auto PPU::Screen::below(bool hires) -> uint16 { auto PPU::Screen::below(bool hires) -> uint16 {
if(ppu.r.displayDisable || (!ppu.r.overscan && ppu.vcounter() >= 225)) return 0; if(ppu.io.displayDisable || (!ppu.io.overscan && ppu.vcounter() >= 225)) return 0;
uint priority = 0; uint priority = 0;
if(ppu.bg1.output.below.priority) { if(ppu.bg1.output.below.priority) {
priority = ppu.bg1.output.below.priority; priority = ppu.bg1.output.below.priority;
if(r.directColor && (ppu.r.bgMode == 3 || ppu.r.bgMode == 4 || ppu.r.bgMode == 7)) { if(io.directColor && (ppu.io.bgMode == 3 || ppu.io.bgMode == 4 || ppu.io.bgMode == 7)) {
math.below.color = directColor(ppu.bg1.output.below.palette, ppu.bg1.output.below.tile); math.below.color = directColor(ppu.bg1.output.below.palette, ppu.bg1.output.below.tile);
} else { } else {
math.below.color = paletteColor(ppu.bg1.output.below.palette); math.below.color = paletteColor(ppu.bg1.output.below.palette);
@ -67,53 +67,53 @@ auto PPU::Screen::below(bool hires) -> uint16 {
} }
auto PPU::Screen::above() -> uint16 { auto PPU::Screen::above() -> uint16 {
if(ppu.r.displayDisable || (!ppu.r.overscan && ppu.vcounter() >= 225)) return 0; if(ppu.io.displayDisable || (!ppu.io.overscan && ppu.vcounter() >= 225)) return 0;
uint priority = 0; uint priority = 0;
if(ppu.bg1.output.above.priority) { if(ppu.bg1.output.above.priority) {
priority = ppu.bg1.output.above.priority; priority = ppu.bg1.output.above.priority;
if(r.directColor && (ppu.r.bgMode == 3 || ppu.r.bgMode == 4 || ppu.r.bgMode == 7)) { if(io.directColor && (ppu.io.bgMode == 3 || ppu.io.bgMode == 4 || ppu.io.bgMode == 7)) {
math.above.color = directColor(ppu.bg1.output.above.palette, ppu.bg1.output.above.tile); math.above.color = directColor(ppu.bg1.output.above.palette, ppu.bg1.output.above.tile);
} else { } else {
math.above.color = paletteColor(ppu.bg1.output.above.palette); math.above.color = paletteColor(ppu.bg1.output.above.palette);
} }
math.below.colorEnable = r.bg1.colorEnable; math.below.colorEnable = io.bg1.colorEnable;
} }
if(ppu.bg2.output.above.priority > priority) { if(ppu.bg2.output.above.priority > priority) {
priority = ppu.bg2.output.above.priority; priority = ppu.bg2.output.above.priority;
math.above.color = paletteColor(ppu.bg2.output.above.palette); math.above.color = paletteColor(ppu.bg2.output.above.palette);
math.below.colorEnable = r.bg2.colorEnable; math.below.colorEnable = io.bg2.colorEnable;
} }
if(ppu.bg3.output.above.priority > priority) { if(ppu.bg3.output.above.priority > priority) {
priority = ppu.bg3.output.above.priority; priority = ppu.bg3.output.above.priority;
math.above.color = paletteColor(ppu.bg3.output.above.palette); math.above.color = paletteColor(ppu.bg3.output.above.palette);
math.below.colorEnable = r.bg3.colorEnable; math.below.colorEnable = io.bg3.colorEnable;
} }
if(ppu.bg4.output.above.priority > priority) { if(ppu.bg4.output.above.priority > priority) {
priority = ppu.bg4.output.above.priority; priority = ppu.bg4.output.above.priority;
math.above.color = paletteColor(ppu.bg4.output.above.palette); math.above.color = paletteColor(ppu.bg4.output.above.palette);
math.below.colorEnable = r.bg4.colorEnable; math.below.colorEnable = io.bg4.colorEnable;
} }
if(ppu.obj.output.above.priority > priority) { if(ppu.obj.output.above.priority > priority) {
priority = ppu.obj.output.above.priority; priority = ppu.obj.output.above.priority;
math.above.color = paletteColor(ppu.obj.output.above.palette); math.above.color = paletteColor(ppu.obj.output.above.palette);
math.below.colorEnable = r.obj.colorEnable && ppu.obj.output.above.palette >= 192; math.below.colorEnable = io.obj.colorEnable && ppu.obj.output.above.palette >= 192;
} }
if(priority == 0) { if(priority == 0) {
math.above.color = paletteColor(0); math.above.color = paletteColor(0);
math.below.colorEnable = r.back.colorEnable; math.below.colorEnable = io.back.colorEnable;
} }
if(!ppu.window.output.below.colorEnable) math.below.colorEnable = false; if(!ppu.window.output.below.colorEnable) math.below.colorEnable = false;
math.above.colorEnable = ppu.window.output.above.colorEnable; math.above.colorEnable = ppu.window.output.above.colorEnable;
if(!math.below.colorEnable) return math.above.colorEnable ? math.above.color : (uint15)0; if(!math.below.colorEnable) return math.above.colorEnable ? math.above.color : (uint15)0;
if(r.blendMode && math.transparent) { if(io.blendMode && math.transparent) {
math.blendMode = false; math.blendMode = false;
math.colorHalve = false; math.colorHalve = false;
} else { } else {
math.blendMode = r.blendMode; math.blendMode = io.blendMode;
math.colorHalve = r.colorHalve && math.above.colorEnable; math.colorHalve = io.colorHalve && math.above.colorEnable;
} }
return blend( return blend(
@ -123,7 +123,7 @@ auto PPU::Screen::above() -> uint16 {
} }
auto PPU::Screen::blend(uint x, uint y) const -> uint15 { auto PPU::Screen::blend(uint x, uint y) const -> uint15 {
if(!r.colorMode) { if(!io.colorMode) {
if(!math.colorHalve) { if(!math.colorHalve) {
uint sum = x + y; uint sum = x + y;
uint carry = (sum - ((x ^ y) & 0x0421)) & 0x8420; uint carry = (sum - ((x ^ y) & 0x0421)) & 0x8420;
@ -144,7 +144,7 @@ auto PPU::Screen::blend(uint x, uint y) const -> uint15 {
auto PPU::Screen::paletteColor(uint8 palette) const -> uint15 { auto PPU::Screen::paletteColor(uint8 palette) const -> uint15 {
ppu.latch.cgramAddress = palette; ppu.latch.cgramAddress = palette;
return ppu.cgram[palette]; return cgram[palette];
} }
auto PPU::Screen::directColor(uint palette, uint tile) const -> uint15 { auto PPU::Screen::directColor(uint palette, uint tile) const -> uint15 {
@ -157,21 +157,23 @@ auto PPU::Screen::directColor(uint palette, uint tile) const -> uint15 {
} }
auto PPU::Screen::fixedColor() const -> uint15 { auto PPU::Screen::fixedColor() const -> uint15 {
return r.colorBlue << 10 | r.colorGreen << 5 | r.colorRed << 0; return io.colorBlue << 10 | io.colorGreen << 5 | io.colorRed << 0;
} }
auto PPU::Screen::reset() -> void { auto PPU::Screen::reset() -> void {
r.blendMode = random(false); for(auto& n : cgram) n = random(0x0000);
r.directColor = random(false);
r.colorMode = random(false); io.blendMode = random(false);
r.colorHalve = random(false); io.directColor = random(false);
r.bg1.colorEnable = random(false); io.colorMode = random(false);
r.bg2.colorEnable = random(false); io.colorHalve = random(false);
r.bg3.colorEnable = random(false); io.bg1.colorEnable = random(false);
r.bg4.colorEnable = random(false); io.bg2.colorEnable = random(false);
r.obj.colorEnable = random(false); io.bg3.colorEnable = random(false);
r.back.colorEnable = random(false); io.bg4.colorEnable = random(false);
r.colorBlue = random(0); io.obj.colorEnable = random(false);
r.colorGreen = random(0); io.back.colorEnable = random(false);
r.colorRed = random(0); io.colorBlue = random(0);
io.colorGreen = random(0);
io.colorRed = random(0);
} }

View File

@ -16,7 +16,9 @@ struct Screen {
uint32* lineA; uint32* lineA;
uint32* lineB; uint32* lineB;
struct Registers { uint15 cgram[256];
struct IO {
bool blendMode; bool blendMode;
bool directColor; bool directColor;
@ -29,7 +31,7 @@ struct Screen {
uint5 colorBlue; uint5 colorBlue;
uint5 colorGreen; uint5 colorGreen;
uint5 colorRed; uint5 colorRed;
} r; } io;
struct Math { struct Math {
struct Screen { struct Screen {

View File

@ -16,8 +16,6 @@ auto PPU::serialize(serializer& s) -> void {
s.integer(vram.mask); s.integer(vram.mask);
s.array(vram.data, vram.mask + 1); s.array(vram.data, vram.mask + 1);
s.array(oam.data);
s.array(cgram.data);
s.integer(ppu1.version); s.integer(ppu1.version);
s.integer(ppu1.mdr); s.integer(ppu1.mdr);
@ -40,46 +38,46 @@ auto PPU::serialize(serializer& s) -> void {
s.integer(latch.oamAddress); s.integer(latch.oamAddress);
s.integer(latch.cgramAddress); s.integer(latch.cgramAddress);
s.integer(r.displayDisable); s.integer(io.displayDisable);
s.integer(r.displayBrightness); s.integer(io.displayBrightness);
s.integer(r.oamBaseAddress); s.integer(io.oamBaseAddress);
s.integer(r.oamAddress); s.integer(io.oamAddress);
s.integer(r.oamPriority); s.integer(io.oamPriority);
s.integer(r.bgPriority); s.integer(io.bgPriority);
s.integer(r.bgMode); s.integer(io.bgMode);
s.integer(r.hoffsetMode7); s.integer(io.hoffsetMode7);
s.integer(r.voffsetMode7); s.integer(io.voffsetMode7);
s.integer(r.vramIncrementMode); s.integer(io.vramIncrementMode);
s.integer(r.vramMapping); s.integer(io.vramMapping);
s.integer(r.vramIncrementSize); s.integer(io.vramIncrementSize);
s.integer(r.vramAddress); s.integer(io.vramAddress);
s.integer(r.repeatMode7); s.integer(io.repeatMode7);
s.integer(r.vflipMode7); s.integer(io.vflipMode7);
s.integer(r.hflipMode7); s.integer(io.hflipMode7);
s.integer(r.m7a); s.integer(io.m7a);
s.integer(r.m7b); s.integer(io.m7b);
s.integer(r.m7c); s.integer(io.m7c);
s.integer(r.m7d); s.integer(io.m7d);
s.integer(r.m7x); s.integer(io.m7x);
s.integer(r.m7y); s.integer(io.m7y);
s.integer(r.cgramAddress); s.integer(io.cgramAddress);
s.integer(r.cgramAddressLatch); s.integer(io.cgramAddressLatch);
s.integer(r.extbg); s.integer(io.extbg);
s.integer(r.pseudoHires); s.integer(io.pseudoHires);
s.integer(r.overscan); s.integer(io.overscan);
s.integer(r.interlace); s.integer(io.interlace);
s.integer(r.hcounter); s.integer(io.hcounter);
s.integer(r.vcounter); s.integer(io.vcounter);
bg1.serialize(s); bg1.serialize(s);
bg2.serialize(s); bg2.serialize(s);
@ -91,20 +89,20 @@ auto PPU::serialize(serializer& s) -> void {
} }
auto PPU::Background::serialize(serializer& s) -> void { auto PPU::Background::serialize(serializer& s) -> void {
s.integer(r.tiledataAddress); s.integer(io.tiledataAddress);
s.integer(r.screenAddress); s.integer(io.screenAddress);
s.integer(r.screenSize); s.integer(io.screenSize);
s.integer(r.mosaic); s.integer(io.mosaic);
s.integer(r.tileSize); s.integer(io.tileSize);
s.integer(r.mode); s.integer(io.mode);
s.array(r.priority); s.array(io.priority);
s.integer(r.aboveEnable); s.integer(io.aboveEnable);
s.integer(r.belowEnable); s.integer(io.belowEnable);
s.integer(r.hoffset); s.integer(io.hoffset);
s.integer(r.voffset); s.integer(io.voffset);
s.integer(latch.hoffset); s.integer(latch.hoffset);
s.integer(latch.voffset); s.integer(latch.voffset);
@ -138,19 +136,31 @@ auto PPU::Background::serialize(serializer& s) -> void {
} }
auto PPU::Object::serialize(serializer& s) -> void { auto PPU::Object::serialize(serializer& s) -> void {
s.integer(r.aboveEnable); for(auto& object : oam.object) {
s.integer(r.belowEnable); s.integer(object.x);
s.integer(r.interlace); s.integer(object.y);
s.integer(object.character);
s.integer(object.nameselect);
s.integer(object.vflip);
s.integer(object.hflip);
s.integer(object.priority);
s.integer(object.palette);
s.integer(object.size);
}
s.integer(r.baseSize); s.integer(io.aboveEnable);
s.integer(r.nameSelect); s.integer(io.belowEnable);
s.integer(r.tiledataAddress); s.integer(io.interlace);
s.integer(r.firstSprite);
s.array(r.priority); s.integer(io.baseSize);
s.integer(io.nameselect);
s.integer(io.tiledataAddress);
s.integer(io.firstSprite);
s.integer(r.timeOver); s.array(io.priority);
s.integer(r.rangeOver);
s.integer(io.timeOver);
s.integer(io.rangeOver);
s.integer(t.x); s.integer(t.x);
s.integer(t.y); s.integer(t.y);
@ -179,73 +189,61 @@ auto PPU::Object::serialize(serializer& s) -> void {
s.integer(output.below.priority); s.integer(output.below.priority);
s.integer(output.below.palette); s.integer(output.below.palette);
for(auto n : range(128)) {
s.integer(list[n].x);
s.integer(list[n].y);
s.integer(list[n].character);
s.integer(list[n].nameSelect);
s.integer(list[n].vflip);
s.integer(list[n].hflip);
s.integer(list[n].priority);
s.integer(list[n].palette);
s.integer(list[n].size);
}
} }
auto PPU::Window::serialize(serializer& s) -> void { auto PPU::Window::serialize(serializer& s) -> void {
s.integer(r.bg1.oneEnable); s.integer(io.bg1.oneEnable);
s.integer(r.bg1.oneInvert); s.integer(io.bg1.oneInvert);
s.integer(r.bg1.twoEnable); s.integer(io.bg1.twoEnable);
s.integer(r.bg1.twoInvert); s.integer(io.bg1.twoInvert);
s.integer(r.bg1.mask); s.integer(io.bg1.mask);
s.integer(r.bg1.aboveEnable); s.integer(io.bg1.aboveEnable);
s.integer(r.bg1.belowEnable); s.integer(io.bg1.belowEnable);
s.integer(r.bg2.oneEnable); s.integer(io.bg2.oneEnable);
s.integer(r.bg2.oneInvert); s.integer(io.bg2.oneInvert);
s.integer(r.bg2.twoEnable); s.integer(io.bg2.twoEnable);
s.integer(r.bg2.twoInvert); s.integer(io.bg2.twoInvert);
s.integer(r.bg2.mask); s.integer(io.bg2.mask);
s.integer(r.bg2.aboveEnable); s.integer(io.bg2.aboveEnable);
s.integer(r.bg2.belowEnable); s.integer(io.bg2.belowEnable);
s.integer(r.bg3.oneEnable); s.integer(io.bg3.oneEnable);
s.integer(r.bg3.oneInvert); s.integer(io.bg3.oneInvert);
s.integer(r.bg3.twoEnable); s.integer(io.bg3.twoEnable);
s.integer(r.bg3.twoInvert); s.integer(io.bg3.twoInvert);
s.integer(r.bg3.mask); s.integer(io.bg3.mask);
s.integer(r.bg3.aboveEnable); s.integer(io.bg3.aboveEnable);
s.integer(r.bg3.belowEnable); s.integer(io.bg3.belowEnable);
s.integer(r.bg4.oneEnable); s.integer(io.bg4.oneEnable);
s.integer(r.bg4.oneInvert); s.integer(io.bg4.oneInvert);
s.integer(r.bg4.twoEnable); s.integer(io.bg4.twoEnable);
s.integer(r.bg4.twoInvert); s.integer(io.bg4.twoInvert);
s.integer(r.bg4.mask); s.integer(io.bg4.mask);
s.integer(r.bg4.aboveEnable); s.integer(io.bg4.aboveEnable);
s.integer(r.bg4.belowEnable); s.integer(io.bg4.belowEnable);
s.integer(r.obj.oneEnable); s.integer(io.obj.oneEnable);
s.integer(r.obj.oneInvert); s.integer(io.obj.oneInvert);
s.integer(r.obj.twoEnable); s.integer(io.obj.twoEnable);
s.integer(r.obj.twoInvert); s.integer(io.obj.twoInvert);
s.integer(r.obj.mask); s.integer(io.obj.mask);
s.integer(r.obj.aboveEnable); s.integer(io.obj.aboveEnable);
s.integer(r.obj.belowEnable); s.integer(io.obj.belowEnable);
s.integer(r.col.oneEnable); s.integer(io.col.oneEnable);
s.integer(r.col.oneInvert); s.integer(io.col.oneInvert);
s.integer(r.col.twoEnable); s.integer(io.col.twoEnable);
s.integer(r.col.twoInvert); s.integer(io.col.twoInvert);
s.integer(r.col.mask); s.integer(io.col.mask);
s.integer(r.col.aboveMask); s.integer(io.col.aboveMask);
s.integer(r.col.belowMask); s.integer(io.col.belowMask);
s.integer(r.oneLeft); s.integer(io.oneLeft);
s.integer(r.oneRight); s.integer(io.oneRight);
s.integer(r.twoLeft); s.integer(io.twoLeft);
s.integer(r.twoRight); s.integer(io.twoRight);
s.integer(output.above.colorEnable); s.integer(output.above.colorEnable);
s.integer(output.below.colorEnable); s.integer(output.below.colorEnable);
@ -254,21 +252,23 @@ auto PPU::Window::serialize(serializer& s) -> void {
} }
auto PPU::Screen::serialize(serializer& s) -> void { auto PPU::Screen::serialize(serializer& s) -> void {
s.integer(r.blendMode); s.array(cgram);
s.integer(r.directColor);
s.integer(r.colorMode); s.integer(io.blendMode);
s.integer(r.colorHalve); s.integer(io.directColor);
s.integer(r.bg1.colorEnable);
s.integer(r.bg2.colorEnable);
s.integer(r.bg3.colorEnable);
s.integer(r.bg4.colorEnable);
s.integer(r.obj.colorEnable);
s.integer(r.back.colorEnable);
s.integer(r.colorBlue); s.integer(io.colorMode);
s.integer(r.colorGreen); s.integer(io.colorHalve);
s.integer(r.colorRed); s.integer(io.bg1.colorEnable);
s.integer(io.bg2.colorEnable);
s.integer(io.bg3.colorEnable);
s.integer(io.bg4.colorEnable);
s.integer(io.obj.colorEnable);
s.integer(io.back.colorEnable);
s.integer(io.colorBlue);
s.integer(io.colorGreen);
s.integer(io.colorRed);
s.integer(math.above.color); s.integer(math.above.color);
s.integer(math.above.colorEnable); s.integer(math.above.colorEnable);

View File

@ -3,39 +3,39 @@ auto PPU::Window::scanline() -> void {
} }
auto PPU::Window::run() -> void { auto PPU::Window::run() -> void {
bool one = (x >= r.oneLeft && x <= r.oneRight); bool one = (x >= io.oneLeft && x <= io.oneRight);
bool two = (x >= r.twoLeft && x <= r.twoRight); bool two = (x >= io.twoLeft && x <= io.twoRight);
x++; x++;
if(test(r.bg1.oneEnable, one ^ r.bg1.oneInvert, r.bg1.twoEnable, two ^ r.bg1.twoInvert, r.bg1.mask)) { if(test(io.bg1.oneEnable, one ^ io.bg1.oneInvert, io.bg1.twoEnable, two ^ io.bg1.twoInvert, io.bg1.mask)) {
if(r.bg1.aboveEnable) ppu.bg1.output.above.priority = 0; if(io.bg1.aboveEnable) ppu.bg1.output.above.priority = 0;
if(r.bg1.belowEnable) ppu.bg1.output.below.priority = 0; if(io.bg1.belowEnable) ppu.bg1.output.below.priority = 0;
} }
if(test(r.bg2.oneEnable, one ^ r.bg2.oneInvert, r.bg2.twoEnable, two ^ r.bg2.twoInvert, r.bg2.mask)) { if(test(io.bg2.oneEnable, one ^ io.bg2.oneInvert, io.bg2.twoEnable, two ^ io.bg2.twoInvert, io.bg2.mask)) {
if(r.bg2.aboveEnable) ppu.bg2.output.above.priority = 0; if(io.bg2.aboveEnable) ppu.bg2.output.above.priority = 0;
if(r.bg2.belowEnable) ppu.bg2.output.below.priority = 0; if(io.bg2.belowEnable) ppu.bg2.output.below.priority = 0;
} }
if(test(r.bg3.oneEnable, one ^ r.bg3.oneInvert, r.bg3.twoEnable, two ^ r.bg3.twoInvert, r.bg3.mask)) { if(test(io.bg3.oneEnable, one ^ io.bg3.oneInvert, io.bg3.twoEnable, two ^ io.bg3.twoInvert, io.bg3.mask)) {
if(r.bg3.aboveEnable) ppu.bg3.output.above.priority = 0; if(io.bg3.aboveEnable) ppu.bg3.output.above.priority = 0;
if(r.bg3.belowEnable) ppu.bg3.output.below.priority = 0; if(io.bg3.belowEnable) ppu.bg3.output.below.priority = 0;
} }
if(test(r.bg4.oneEnable, one ^ r.bg4.oneInvert, r.bg4.twoEnable, two ^ r.bg4.twoInvert, r.bg4.mask)) { if(test(io.bg4.oneEnable, one ^ io.bg4.oneInvert, io.bg4.twoEnable, two ^ io.bg4.twoInvert, io.bg4.mask)) {
if(r.bg4.aboveEnable) ppu.bg4.output.above.priority = 0; if(io.bg4.aboveEnable) ppu.bg4.output.above.priority = 0;
if(r.bg4.belowEnable) ppu.bg4.output.below.priority = 0; if(io.bg4.belowEnable) ppu.bg4.output.below.priority = 0;
} }
if(test(r.obj.oneEnable, one ^ r.obj.oneInvert, r.obj.twoEnable, two ^ r.obj.twoInvert, r.obj.mask)) { if(test(io.obj.oneEnable, one ^ io.obj.oneInvert, io.obj.twoEnable, two ^ io.obj.twoInvert, io.obj.mask)) {
if(r.obj.aboveEnable) ppu.obj.output.above.priority = 0; if(io.obj.aboveEnable) ppu.obj.output.above.priority = 0;
if(r.obj.belowEnable) ppu.obj.output.below.priority = 0; if(io.obj.belowEnable) ppu.obj.output.below.priority = 0;
} }
bool value = test(r.col.oneEnable, one ^ r.col.oneInvert, r.col.twoEnable, two ^ r.col.twoInvert, r.col.mask); bool value = test(io.col.oneEnable, one ^ io.col.oneInvert, io.col.twoEnable, two ^ io.col.twoInvert, io.col.mask);
bool array[] = {true, value, !value, false}; bool array[] = {true, value, !value, false};
output.above.colorEnable = array[r.col.aboveMask]; output.above.colorEnable = array[io.col.aboveMask];
output.below.colorEnable = array[r.col.belowMask]; output.below.colorEnable = array[io.col.belowMask];
} }
auto PPU::Window::test(bool oneEnable, bool one, bool twoEnable, bool two, uint mask) -> bool { auto PPU::Window::test(bool oneEnable, bool one, bool twoEnable, bool two, uint mask) -> bool {
@ -47,58 +47,58 @@ auto PPU::Window::test(bool oneEnable, bool one, bool twoEnable, bool two, uint
} }
auto PPU::Window::reset() -> void { auto PPU::Window::reset() -> void {
r.bg1.oneEnable = random(false); io.bg1.oneEnable = random(false);
r.bg1.oneInvert = random(false); io.bg1.oneInvert = random(false);
r.bg1.twoEnable = random(false); io.bg1.twoEnable = random(false);
r.bg1.twoInvert = random(false); io.bg1.twoInvert = random(false);
r.bg1.mask = random(0); io.bg1.mask = random(0);
r.bg1.aboveEnable = random(false); io.bg1.aboveEnable = random(false);
r.bg1.belowEnable = random(false); io.bg1.belowEnable = random(false);
r.bg2.oneEnable = random(false); io.bg2.oneEnable = random(false);
r.bg2.oneInvert = random(false); io.bg2.oneInvert = random(false);
r.bg2.twoEnable = random(false); io.bg2.twoEnable = random(false);
r.bg2.twoInvert = random(false); io.bg2.twoInvert = random(false);
r.bg2.mask = random(0); io.bg2.mask = random(0);
r.bg2.aboveEnable = random(false); io.bg2.aboveEnable = random(false);
r.bg2.belowEnable = random(false); io.bg2.belowEnable = random(false);
r.bg3.oneEnable = random(false); io.bg3.oneEnable = random(false);
r.bg3.oneInvert = random(false); io.bg3.oneInvert = random(false);
r.bg3.twoEnable = random(false); io.bg3.twoEnable = random(false);
r.bg3.twoInvert = random(false); io.bg3.twoInvert = random(false);
r.bg3.mask = random(0); io.bg3.mask = random(0);
r.bg3.aboveEnable = random(false); io.bg3.aboveEnable = random(false);
r.bg3.belowEnable = random(false); io.bg3.belowEnable = random(false);
r.bg4.oneEnable = random(false); io.bg4.oneEnable = random(false);
r.bg4.oneInvert = random(false); io.bg4.oneInvert = random(false);
r.bg4.twoEnable = random(false); io.bg4.twoEnable = random(false);
r.bg4.twoInvert = random(false); io.bg4.twoInvert = random(false);
r.bg4.mask = random(0); io.bg4.mask = random(0);
r.bg4.aboveEnable = random(false); io.bg4.aboveEnable = random(false);
r.bg4.belowEnable = random(false); io.bg4.belowEnable = random(false);
r.obj.oneEnable = random(false); io.obj.oneEnable = random(false);
r.obj.oneInvert = random(false); io.obj.oneInvert = random(false);
r.obj.twoEnable = random(false); io.obj.twoEnable = random(false);
r.obj.twoInvert = random(false); io.obj.twoInvert = random(false);
r.obj.mask = random(0); io.obj.mask = random(0);
r.obj.aboveEnable = random(false); io.obj.aboveEnable = random(false);
r.obj.belowEnable = random(false); io.obj.belowEnable = random(false);
r.col.oneEnable = random(false); io.col.oneEnable = random(false);
r.col.oneInvert = random(false); io.col.oneInvert = random(false);
r.col.twoEnable = random(false); io.col.twoEnable = random(false);
r.col.twoInvert = random(false); io.col.twoInvert = random(false);
r.col.mask = random(0); io.col.mask = random(0);
r.col.aboveMask = random(0); io.col.aboveMask = random(0);
r.col.belowMask = random(0); io.col.belowMask = random(0);
r.oneLeft = random(0x00); io.oneLeft = random(0x00);
r.oneRight = random(0x00); io.oneRight = random(0x00);
r.twoLeft = random(0x00); io.twoLeft = random(0x00);
r.twoRight = random(0x00); io.twoRight = random(0x00);
output.above.colorEnable = 0; output.above.colorEnable = 0;
output.below.colorEnable = 0; output.below.colorEnable = 0;

View File

@ -6,7 +6,7 @@ struct Window {
auto serialize(serializer&) -> void; auto serialize(serializer&) -> void;
struct Registers { struct IO {
struct Layer { struct Layer {
bool oneEnable; bool oneEnable;
bool oneInvert; bool oneInvert;
@ -31,7 +31,7 @@ struct Window {
uint8 oneRight; uint8 oneRight;
uint8 twoLeft; uint8 twoLeft;
uint8 twoRight; uint8 twoRight;
} r; } io;
struct Output { struct Output {
struct Pixel { struct Pixel {

View File

@ -1,12 +1,12 @@
alwaysinline auto SMP::readRAM(uint16 addr) -> uint8 { alwaysinline auto SMP::readRAM(uint16 addr) -> uint8 {
if(addr >= 0xffc0 && status.iplromEnable) return iplrom[addr & 0x3f]; if(addr >= 0xffc0 && io.iplromEnable) return iplrom[addr & 0x3f];
if(status.ramDisable) return 0x5a; //0xff on mini-SNES if(io.ramDisable) return 0x5a; //0xff on mini-SNES
return apuram[addr]; return apuram[addr];
} }
alwaysinline auto SMP::writeRAM(uint16 addr, uint8 data) -> void { alwaysinline auto SMP::writeRAM(uint16 addr, uint8 data) -> void {
//writes to $ffc0-$ffff always go to apuram, even if the iplrom is enabled //writes to $ffc0-$ffff always go to apuram, even if the iplrom is enabled
if(status.ramWritable && !status.ramDisable) apuram[addr] = data; if(io.ramWritable && !io.ramDisable) apuram[addr] = data;
} }
auto SMP::readPort(uint2 port) const -> uint8 { auto SMP::readPort(uint2 port) const -> uint8 {
@ -28,24 +28,24 @@ auto SMP::readBus(uint16 addr) -> uint8 {
return 0x00; return 0x00;
case 0xf2: //DSPADDR case 0xf2: //DSPADDR
return status.dspAddr; return io.dspAddr;
case 0xf3: //DSPDATA case 0xf3: //DSPDATA
//0x80-0xff are read-only mirrors of 0x00-0x7f //0x80-0xff are read-only mirrors of 0x00-0x7f
return dsp.read(status.dspAddr & 0x7f); return dsp.read(io.dspAddr & 0x7f);
case 0xf4: //CPUIO0 case 0xf4: //CPUIO0
case 0xf5: //CPUIO1 case 0xf5: //CPUIO1
case 0xf6: //CPUIO2 case 0xf6: //CPUIO2
case 0xf7: //CPUIO3 case 0xf7: //CPUIO3
synchronizeCPU(); synchronizeCPU();
return cpu.portRead(addr); return cpu.readPort(addr);
case 0xf8: //RAM0 case 0xf8: //RAM0
return status.ram00f8; return io.ram00f8;
case 0xf9: //RAM1 case 0xf9: //RAM1
return status.ram00f9; return io.ram00f9;
case 0xfa: //T0TARGET case 0xfa: //T0TARGET
case 0xfb: //T1TARGET case 0xfb: //T1TARGET
@ -76,14 +76,14 @@ auto SMP::writeBus(uint16 addr, uint8 data) -> void {
case 0xf0: //TEST case 0xf0: //TEST
if(regs.p.p) break; //writes only valid when P flag is clear if(regs.p.p) break; //writes only valid when P flag is clear
status.clockSpeed = (data >> 6) & 3; io.clockSpeed = (data >> 6) & 3;
status.timerSpeed = (data >> 4) & 3; io.timerSpeed = (data >> 4) & 3;
status.timersEnable = data & 0x08; io.timersEnable = data & 0x08;
status.ramDisable = data & 0x04; io.ramDisable = data & 0x04;
status.ramWritable = data & 0x02; io.ramWritable = data & 0x02;
status.timersDisable = data & 0x01; io.timersDisable = data & 0x01;
status.timerStep = (1 << status.clockSpeed) + (2 << status.timerSpeed); io.timerStep = (1 << io.clockSpeed) + (2 << io.timerSpeed);
timer0.synchronizeStage1(); timer0.synchronizeStage1();
timer1.synchronizeStage1(); timer1.synchronizeStage1();
@ -91,19 +91,19 @@ auto SMP::writeBus(uint16 addr, uint8 data) -> void {
break; break;
case 0xf1: //CONTROL case 0xf1: //CONTROL
status.iplromEnable = data & 0x80; io.iplromEnable = data & 0x80;
if(data & 0x30) { if(data & 0x30) {
//one-time clearing of APU port read registers, //one-time clearing of APU port read registers,
//emulated by simulating CPU writes of 0x00 //emulated by simulating CPU writes of 0x00
synchronizeCPU(); synchronizeCPU();
if(data & 0x20) { if(data & 0x20) {
cpu.portWrite(2, 0x00); cpu.writePort(2, 0x00);
cpu.portWrite(3, 0x00); cpu.writePort(3, 0x00);
} }
if(data & 0x10) { if(data & 0x10) {
cpu.portWrite(0, 0x00); cpu.writePort(0, 0x00);
cpu.portWrite(1, 0x00); cpu.writePort(1, 0x00);
} }
} }
@ -128,12 +128,12 @@ auto SMP::writeBus(uint16 addr, uint8 data) -> void {
break; break;
case 0xf2: //DSPADDR case 0xf2: //DSPADDR
status.dspAddr = data; io.dspAddr = data;
break; break;
case 0xf3: //DSPDATA case 0xf3: //DSPDATA
if(status.dspAddr & 0x80) break; //0x80-0xff are read-only mirrors of 0x00-0x7f if(io.dspAddr & 0x80) break; //0x80-0xff are read-only mirrors of 0x00-0x7f
dsp.write(status.dspAddr & 0x7f, data); dsp.write(io.dspAddr & 0x7f, data);
break; break;
case 0xf4: //CPUIO0 case 0xf4: //CPUIO0
@ -145,11 +145,11 @@ auto SMP::writeBus(uint16 addr, uint8 data) -> void {
break; break;
case 0xf8: //RAM0 case 0xf8: //RAM0
status.ram00f8 = data; io.ram00f8 = data;
break; break;
case 0xf9: //RAM1 case 0xf9: //RAM1
status.ram00f9 = data; io.ram00f9 = data;
break; break;
case 0xfa: //T0TARGET case 0xfa: //T0TARGET
@ -173,27 +173,27 @@ auto SMP::writeBus(uint16 addr, uint8 data) -> void {
writeRAM(addr, data); //all writes, even to MMIO registers, appear on bus writeRAM(addr, data); //all writes, even to MMIO registers, appear on bus
} }
auto SMP::io() -> void { auto SMP::idle() -> void {
addClocks(24); step(24);
cycleEdge(); cycleEdge();
} }
auto SMP::read(uint16 addr) -> uint8 { auto SMP::read(uint16 addr) -> uint8 {
addClocks(12); step(12);
uint8 data = readBus(addr); uint8 data = readBus(addr);
addClocks(12); step(12);
cycleEdge(); cycleEdge();
return data; return data;
} }
auto SMP::write(uint16 addr, uint8 data) -> void { auto SMP::write(uint16 addr, uint8 data) -> void {
addClocks(24); step(24);
writeBus(addr, data); writeBus(addr, data);
cycleEdge(); cycleEdge();
} }
auto SMP::readDisassembler(uint16 addr) -> uint8 { auto SMP::readDisassembler(uint16 addr) -> uint8 {
if((addr & 0xfff0) == 0x00f0) return 0x00; if((addr & 0xfff0) == 0x00f0) return 0x00;
if((addr & 0xffc0) == 0xffc0 && status.iplromEnable) return iplrom[addr & 0x3f]; if((addr & 0xffc0) == 0xffc0 && io.iplromEnable) return iplrom[addr & 0x3f];
return apuram[addr]; return apuram[addr];
} }

View File

@ -4,23 +4,23 @@ auto SMP::serialize(serializer& s) -> void {
s.array(apuram); s.array(apuram);
s.integer(status.clockCounter); s.integer(io.clockCounter);
s.integer(status.dspCounter); s.integer(io.dspCounter);
s.integer(status.timerStep); s.integer(io.timerStep);
s.integer(status.clockSpeed); s.integer(io.clockSpeed);
s.integer(status.timerSpeed); s.integer(io.timerSpeed);
s.integer(status.timersEnable); s.integer(io.timersEnable);
s.integer(status.ramDisable); s.integer(io.ramDisable);
s.integer(status.ramWritable); s.integer(io.ramWritable);
s.integer(status.timersDisable); s.integer(io.timersDisable);
s.integer(status.iplromEnable); s.integer(io.iplromEnable);
s.integer(status.dspAddr); s.integer(io.dspAddr);
s.integer(status.ram00f8); s.integer(io.ram00f8);
s.integer(status.ram00f9); s.integer(io.ram00f9);
s.integer(timer0.stage0); s.integer(timer0.stage0);
s.integer(timer0.stage1); s.integer(timer0.stage1);

View File

@ -8,11 +8,6 @@ SMP smp;
#include "timing.cpp" #include "timing.cpp"
#include "serialization.cpp" #include "serialization.cpp"
auto SMP::step(uint clocks) -> void {
clock += clocks * (uint64)cpu.frequency;
dsp.clock -= clocks;
}
auto SMP::synchronizeCPU() -> void { auto SMP::synchronizeCPU() -> void {
if(clock >= 0 && !scheduler.synchronizing()) co_switch(cpu.thread); if(clock >= 0 && !scheduler.synchronizing()) co_switch(cpu.thread);
} }
@ -63,27 +58,27 @@ auto SMP::reset() -> void {
apuram[0x00f6] = 0x00; apuram[0x00f6] = 0x00;
apuram[0x00f7] = 0x00; apuram[0x00f7] = 0x00;
status.clockCounter = 0; io.clockCounter = 0;
status.dspCounter = 0; io.dspCounter = 0;
status.timerStep = 3; io.timerStep = 3;
//$00f0 //$00f0
status.clockSpeed = 0; io.clockSpeed = 0;
status.timerSpeed = 0; io.timerSpeed = 0;
status.timersEnable = true; io.timersEnable = true;
status.ramDisable = false; io.ramDisable = false;
status.ramWritable = true; io.ramWritable = true;
status.timersDisable = false; io.timersDisable = false;
//$00f1 //$00f1
status.iplromEnable = true; io.iplromEnable = true;
//$00f2 //$00f2
status.dspAddr = 0x00; io.dspAddr = 0x00;
//$00f8,$00f9 //$00f8,$00f9
status.ram00f8 = 0x00; io.ram00f8 = 0x00;
status.ram00f9 = 0x00; io.ram00f9 = 0x00;
timer0.stage0 = 0; timer0.stage0 = 0;
timer1.stage0 = 0; timer1.stage0 = 0;

View File

@ -1,7 +1,6 @@
//Sony CXP1100Q-1 //Sony CXP1100Q-1
struct SMP : Processor::SPC700, Thread { struct SMP : Processor::SPC700, Thread {
alwaysinline auto step(uint clocks) -> void;
alwaysinline auto synchronizeCPU() -> void; alwaysinline auto synchronizeCPU() -> void;
alwaysinline auto synchronizeDSP() -> void; alwaysinline auto synchronizeDSP() -> void;
@ -19,7 +18,7 @@ struct SMP : Processor::SPC700, Thread {
uint8 apuram[64 * 1024]; uint8 apuram[64 * 1024];
privileged: privileged:
struct { struct IO {
//timing //timing
uint clockCounter; uint clockCounter;
uint dspCounter; uint dspCounter;
@ -42,7 +41,7 @@ privileged:
//$00f8,$00f9 //$00f8,$00f9
uint8 ram00f8; uint8 ram00f8;
uint8 ram00f9; uint8 ram00f9;
} status; } io;
static auto Enter() -> void; static auto Enter() -> void;
@ -53,15 +52,14 @@ privileged:
auto readBus(uint16 addr) -> uint8; auto readBus(uint16 addr) -> uint8;
auto writeBus(uint16 addr, uint8 data) -> void; auto writeBus(uint16 addr, uint8 data) -> void;
auto io() -> void override; auto idle() -> void override;
auto read(uint16 addr) -> uint8 override; auto read(uint16 addr) -> uint8 override;
auto write(uint16 addr, uint8 data) -> void override; auto write(uint16 addr, uint8 data) -> void override;
auto readDisassembler(uint16 addr) -> uint8 override; auto readDisassembler(uint16 addr) -> uint8 override;
//timing.cpp //timing.cpp
template<uint Frequency> template<uint Frequency> struct Timer {
struct Timer {
uint8 stage0; uint8 stage0;
uint8 stage1; uint8 stage1;
uint8 stage2; uint8 stage2;
@ -78,7 +76,7 @@ privileged:
Timer<192> timer1; Timer<192> timer1;
Timer< 24> timer2; Timer< 24> timer2;
alwaysinline auto addClocks(uint clocks) -> void; alwaysinline auto step(uint clocks) -> void;
alwaysinline auto cycleEdge() -> void; alwaysinline auto cycleEdge() -> void;
}; };

View File

@ -1,5 +1,6 @@
auto SMP::addClocks(uint clocks) -> void { auto SMP::step(uint clocks) -> void {
step(clocks); clock += clocks * (uint64)cpu.frequency;
dsp.clock -= clocks;
synchronizeDSP(); synchronizeDSP();
#if defined(DEBUGGER) #if defined(DEBUGGER)
@ -18,18 +19,17 @@ auto SMP::cycleEdge() -> void {
//TEST register S-SMP speed control //TEST register S-SMP speed control
//24 clocks have already been added for this cycle at this point //24 clocks have already been added for this cycle at this point
switch(status.clockSpeed) { switch(io.clockSpeed) {
case 0: break; //100% speed case 0: break; //100% speed
case 1: addClocks(24); break; // 50% speed case 1: step(24); break; // 50% speed
case 2: while(true) addClocks(24); // 0% speed -- locks S-SMP case 2: while(true) step(24); // 0% speed -- locks S-SMP
case 3: addClocks(24 * 9); break; // 10% speed case 3: step(24 * 9); break; // 10% speed
} }
} }
template<unsigned Frequency> template<uint Frequency> auto SMP::Timer<Frequency>::tick() -> void {
auto SMP::Timer<Frequency>::tick() -> void {
//stage 0 increment //stage 0 increment
stage0 += smp.status.timerStep; stage0 += smp.io.timerStep;
if(stage0 < Frequency) return; if(stage0 < Frequency) return;
stage0 -= Frequency; stage0 -= Frequency;
@ -38,18 +38,17 @@ auto SMP::Timer<Frequency>::tick() -> void {
synchronizeStage1(); synchronizeStage1();
} }
template<unsigned Frequency> template<uint Frequency> auto SMP::Timer<Frequency>::synchronizeStage1() -> void {
auto SMP::Timer<Frequency>::synchronizeStage1() -> void {
bool newLine = stage1; bool newLine = stage1;
if(smp.status.timersEnable == false) newLine = false; if(!smp.io.timersEnable) newLine = false;
if(smp.status.timersDisable == true) newLine = false; if(smp.io.timersDisable) newLine = false;
bool oldLine = line; bool oldLine = line;
line = newLine; line = newLine;
if(oldLine != 1 || newLine != 0) return; //only pulse on 1->0 transition if(oldLine != 1 || newLine != 0) return; //only pulse on 1->0 transition
//stage 2 increment //stage 2 increment
if(enable == false) return; if(!enable) return;
if(++stage2 != target) return; if(++stage2 != target) return;
//stage 3 increment //stage 3 increment

View File

@ -105,7 +105,7 @@ auto Program::inputRumble(uint port, uint device, uint input, bool enable) -> vo
} }
} }
auto Program::dipSettings(const Markup::Node& node) -> uint { auto Program::dipSettings(Markup::Node node) -> uint {
return 0; return 0;
} }

View File

@ -12,7 +12,7 @@ struct Program : Emulator::Interface::Bind {
auto audioSample(const double* samples, uint channels) -> void override; auto audioSample(const double* samples, uint channels) -> void override;
auto inputPoll(uint port, uint device, uint input) -> int16 override; auto inputPoll(uint port, uint device, uint input) -> int16 override;
auto inputRumble(uint port, uint device, uint input, bool enable) -> void override; auto inputRumble(uint port, uint device, uint input, bool enable) -> void override;
auto dipSettings(const Markup::Node& node) -> uint override; auto dipSettings(Markup::Node node) -> uint override;
auto notify(string text) -> void override; auto notify(string text) -> void override;
//medium.cpp //medium.cpp

View File

@ -2,7 +2,7 @@ auto Program::stateName(uint slot, bool manager) -> string {
return { return {
mediumPaths(1), "higan/states/", mediumPaths(1), "higan/states/",
manager ? "managed/" : "quick/", manager ? "managed/" : "quick/",
"slot-", natural(slot, 2L), ".bst" "slot-", numeral(slot, 2L), ".bst"
}; };
} }

View File

@ -146,8 +146,8 @@ auto Interface::cheatSet(const lstring& list) -> void {
lstring codes = codeset.split("+"); lstring codes = codeset.split("+");
for(auto& code : codes) { for(auto& code : codes) {
lstring part = code.split("/"); lstring part = code.split("/");
if(part.size() == 2) cheat.append(hex(part[0]), hex(part[1])); if(part.size() == 2) cheat.append(part[0].hex(), part[1].hex());
if(part.size() == 3) cheat.append(hex(part[0]), hex(part[1]), hex(part[2])); if(part.size() == 3) cheat.append(part[0].hex(), part[1].hex(), part[2].hex());
} }
} }
} }

View File

@ -53,8 +53,8 @@ auto pViewport::destruct() -> void {
} }
} }
auto pViewport::handle() const -> uintptr { auto pViewport::handle() const -> uintptr_t {
return (uintptr)cocoaViewport; return (uintptr_t)cocoaViewport;
} }
auto pViewport::setDroppable(bool droppable) -> void { auto pViewport::setDroppable(bool droppable) -> void {

View File

@ -18,7 +18,7 @@ namespace hiro {
struct pViewport : pWidget { struct pViewport : pWidget {
Declare(Viewport, Widget) Declare(Viewport, Widget)
auto handle() const -> uintptr; auto handle() const -> uintptr_t;
auto setDroppable(bool droppable) -> void; auto setDroppable(bool droppable) -> void;
CocoaViewport* cocoaViewport = nullptr; CocoaViewport* cocoaViewport = nullptr;

View File

@ -193,7 +193,7 @@ auto pIconView::_updateSelected() -> void {
while(p) { while(p) {
auto path = (GtkTreePath*)p->data; auto path = (GtkTreePath*)p->data;
char* pathString = gtk_tree_path_to_string(path); char* pathString = gtk_tree_path_to_string(path);
unsigned position = natural(pathString); unsigned position = toNatural(pathString);
g_free(pathString); g_free(pathString);
selected.append(position); selected.append(position);
p = p->next; p = p->next;

View File

@ -218,7 +218,7 @@ auto pTableView::_doContext() -> void {
auto pTableView::_doDataFunc(GtkTreeViewColumn* gtkColumn, GtkCellRenderer* renderer, GtkTreeIter* iter) -> void { auto pTableView::_doDataFunc(GtkTreeViewColumn* gtkColumn, GtkCellRenderer* renderer, GtkTreeIter* iter) -> void {
auto path = gtk_tree_model_get_string_from_iter(gtkTreeModel, iter); auto path = gtk_tree_model_get_string_from_iter(gtkTreeModel, iter);
auto row = natural(path); auto row = toNatural(path);
g_free(path); g_free(path);
if(auto& header = state().header) { if(auto& header = state().header) {
@ -271,7 +271,7 @@ auto pTableView::_doEdit(GtkCellRendererText* gtkCellRendererText, const char* p
for(auto& column : header->state.columns) { for(auto& column : header->state.columns) {
if(auto delegate = column->self()) { if(auto delegate = column->self()) {
if(gtkCellRendererText == GTK_CELL_RENDERER_TEXT(delegate->gtkCellText)) { if(gtkCellRendererText == GTK_CELL_RENDERER_TEXT(delegate->gtkCellText)) {
auto row = natural(path); auto row = toNatural(path);
if(auto item = self().item(row)) { if(auto item = self().item(row)) {
if(auto cell = item->cell(column->offset())) { if(auto cell = item->cell(column->offset())) {
if(string{text} != cell->state.text) { if(string{text} != cell->state.text) {
@ -343,7 +343,7 @@ auto pTableView::_doToggle(GtkCellRendererToggle* gtkCellRendererToggle, const c
for(auto& column : header->state.columns) { for(auto& column : header->state.columns) {
if(auto delegate = column->self()) { if(auto delegate = column->self()) {
if(gtkCellRendererToggle == GTK_CELL_RENDERER_TOGGLE(delegate->gtkCellToggle)) { if(gtkCellRendererToggle == GTK_CELL_RENDERER_TOGGLE(delegate->gtkCellToggle)) {
auto row = natural(path); auto row = toNatural(path);
if(auto item = self().item(row)) { if(auto item = self().item(row)) {
if(auto cell = item->cell(column->offset())) { if(auto cell = item->cell(column->offset())) {
cell->setChecked(!cell->checked()); cell->setChecked(!cell->checked());
@ -371,7 +371,7 @@ auto pTableView::_updateSelected() -> void {
GtkTreeIter iter; GtkTreeIter iter;
if(gtk_tree_model_get_iter(gtkTreeModel, &iter, (GtkTreePath*)p->data)) { if(gtk_tree_model_get_iter(gtkTreeModel, &iter, (GtkTreePath*)p->data)) {
char* pathname = gtk_tree_model_get_string_from_iter(gtkTreeModel, &iter); char* pathname = gtk_tree_model_get_string_from_iter(gtkTreeModel, &iter);
unsigned selection = natural(pathname); unsigned selection = toNatural(pathname);
g_free(pathname); g_free(pathname);
selected.append(selection); selected.append(selection);
} }

View File

@ -4,83 +4,83 @@
namespace nall { namespace nall {
constexpr inline auto binary_(const char* s, uintmax sum = 0) -> uintmax { constexpr inline auto toBinary_(const char* s, uintmax_t sum = 0) -> uintmax_t {
return ( return (
*s == '0' || *s == '1' ? binary_(s + 1, (sum << 1) | *s - '0') : *s == '0' || *s == '1' ? toBinary_(s + 1, (sum << 1) | *s - '0') :
*s == '\'' ? binary_(s + 1, sum) : *s == '\'' ? toBinary_(s + 1, sum) :
sum sum
); );
} }
constexpr inline auto octal_(const char* s, uintmax sum = 0) -> uintmax { constexpr inline auto toOctal_(const char* s, uintmax_t sum = 0) -> uintmax_t {
return ( return (
*s >= '0' && *s <= '7' ? octal_(s + 1, (sum << 3) | *s - '0') : *s >= '0' && *s <= '7' ? toOctal_(s + 1, (sum << 3) | *s - '0') :
*s == '\'' ? octal_(s + 1, sum) : *s == '\'' ? toOctal_(s + 1, sum) :
sum sum
); );
} }
constexpr inline auto decimal_(const char* s, uintmax sum = 0) -> uintmax { constexpr inline auto toDecimal_(const char* s, uintmax_t sum = 0) -> uintmax_t {
return ( return (
*s >= '0' && *s <= '9' ? decimal_(s + 1, (sum * 10) + *s - '0') : *s >= '0' && *s <= '9' ? toDecimal_(s + 1, (sum * 10) + *s - '0') :
*s == '\'' ? decimal_(s + 1, sum) : *s == '\'' ? toDecimal_(s + 1, sum) :
sum sum
); );
} }
constexpr inline auto hex_(const char* s, uintmax sum = 0) -> uintmax { constexpr inline auto toHex_(const char* s, uintmax_t sum = 0) -> uintmax_t {
return ( return (
*s >= 'A' && *s <= 'F' ? hex_(s + 1, (sum << 4) | *s - 'A' + 10) : *s >= 'A' && *s <= 'F' ? toHex_(s + 1, (sum << 4) | *s - 'A' + 10) :
*s >= 'a' && *s <= 'f' ? hex_(s + 1, (sum << 4) | *s - 'a' + 10) : *s >= 'a' && *s <= 'f' ? toHex_(s + 1, (sum << 4) | *s - 'a' + 10) :
*s >= '0' && *s <= '9' ? hex_(s + 1, (sum << 4) | *s - '0') : *s >= '0' && *s <= '9' ? toHex_(s + 1, (sum << 4) | *s - '0') :
*s == '\'' ? hex_(s + 1, sum) : *s == '\'' ? toHex_(s + 1, sum) :
sum sum
); );
} }
// //
constexpr inline auto binary(const char* s) -> uintmax { constexpr inline auto toBinary(const char* s) -> uintmax_t {
return ( return (
*s == '0' && (*(s + 1) == 'B' || *(s + 1) == 'b') ? binary_(s + 2) : *s == '0' && (*(s + 1) == 'B' || *(s + 1) == 'b') ? toBinary_(s + 2) :
*s == '%' ? binary_(s + 1) : binary_(s) *s == '%' ? toBinary_(s + 1) : toBinary_(s)
); );
} }
constexpr inline auto octal(const char* s) -> uintmax { constexpr inline auto toOctal(const char* s) -> uintmax_t {
return ( return (
*s == '0' && (*(s + 1) == 'O' || *(s + 1) == 'o') ? octal_(s + 2) : *s == '0' && (*(s + 1) == 'O' || *(s + 1) == 'o') ? toOctal_(s + 2) :
octal_(s) toOctal_(s)
); );
} }
constexpr inline auto hex(const char* s) -> uintmax { constexpr inline auto toHex(const char* s) -> uintmax_t {
return ( return (
*s == '0' && (*(s + 1) == 'X' || *(s + 1) == 'x') ? hex_(s + 2) : *s == '0' && (*(s + 1) == 'X' || *(s + 1) == 'x') ? toHex_(s + 2) :
*s == '$' ? hex_(s + 1) : hex_(s) *s == '$' ? toHex_(s + 1) : toHex_(s)
); );
} }
// //
constexpr inline auto natural(const char* s) -> uintmax { constexpr inline auto toNatural(const char* s) -> uintmax_t {
return ( return (
*s == '0' && (*(s + 1) == 'B' || *(s + 1) == 'b') ? binary_(s + 2) : *s == '0' && (*(s + 1) == 'B' || *(s + 1) == 'b') ? toBinary_(s + 2) :
*s == '0' && (*(s + 1) == 'O' || *(s + 1) == 'o') ? octal_(s + 2) : *s == '0' && (*(s + 1) == 'O' || *(s + 1) == 'o') ? toOctal_(s + 2) :
*s == '0' && (*(s + 1) == 'X' || *(s + 1) == 'x') ? hex_(s + 2) : *s == '0' && (*(s + 1) == 'X' || *(s + 1) == 'x') ? toHex_(s + 2) :
*s == '%' ? binary_(s + 1) : *s == '$' ? hex_(s + 1) : decimal_(s) *s == '%' ? toBinary_(s + 1) : *s == '$' ? toHex_(s + 1) : toDecimal_(s)
); );
} }
constexpr inline auto integer(const char* s) -> intmax { constexpr inline auto toInteger(const char* s) -> intmax_t {
return ( return (
*s == '+' ? +natural(s + 1) : *s == '-' ? -natural(s + 1) : natural(s) *s == '+' ? +toNatural(s + 1) : *s == '-' ? -toNatural(s + 1) : toNatural(s)
); );
} }
// //
inline auto real(const char* s) -> double { inline auto toReal(const char* s) -> double {
return atof(s); return atof(s);
} }

View File

@ -4,28 +4,28 @@
namespace nall { namespace nall {
template<uint bits> inline auto uclamp(const uintmax x) -> uintmax { template<uint bits> inline auto uclamp(const uintmax_t x) -> uintmax_t {
enum : uintmax { b = 1ull << (bits - 1), y = b * 2 - 1 }; enum : uintmax_t { b = 1ull << (bits - 1), y = b * 2 - 1 };
return y + ((x - y) & -(x < y)); //min(x, y); return y + ((x - y) & -(x < y)); //min(x, y);
} }
template<uint bits> inline auto uclip(const uintmax x) -> uintmax { template<uint bits> inline auto uclip(const uintmax_t x) -> uintmax_t {
enum : uintmax { b = 1ull << (bits - 1), m = b * 2 - 1 }; enum : uintmax_t { b = 1ull << (bits - 1), m = b * 2 - 1 };
return (x & m); return (x & m);
} }
template<uint bits> inline auto sclamp(const intmax x) -> intmax { template<uint bits> inline auto sclamp(const intmax_t x) -> intmax_t {
enum : intmax { b = 1ull << (bits - 1), m = b - 1 }; enum : intmax_t { b = 1ull << (bits - 1), m = b - 1 };
return (x > m) ? m : (x < -b) ? -b : x; return (x > m) ? m : (x < -b) ? -b : x;
} }
template<uint bits> inline auto sclip(const intmax x) -> intmax { template<uint bits> inline auto sclip(const intmax_t x) -> intmax_t {
enum : uintmax { b = 1ull << (bits - 1), m = b * 2 - 1 }; enum : uintmax_t { b = 1ull << (bits - 1), m = b * 2 - 1 };
return ((x & m) ^ b) - b; return ((x & m) ^ b) - b;
} }
namespace bit { namespace bit {
constexpr inline auto mask(const char* s, uintmax sum = 0) -> uintmax { constexpr inline auto mask(const char* s, uintmax_t sum = 0) -> uintmax_t {
return ( return (
*s == '0' || *s == '1' ? mask(s + 1, (sum << 1) | 1) : *s == '0' || *s == '1' ? mask(s + 1, (sum << 1) | 1) :
*s == ' ' || *s == '_' ? mask(s + 1, sum) : *s == ' ' || *s == '_' ? mask(s + 1, sum) :
@ -34,7 +34,7 @@ namespace bit {
); );
} }
constexpr inline auto test(const char* s, uintmax sum = 0) -> uintmax { constexpr inline auto test(const char* s, uintmax_t sum = 0) -> uintmax_t {
return ( return (
*s == '0' || *s == '1' ? test(s + 1, (sum << 1) | (*s - '0')) : *s == '0' || *s == '1' ? test(s + 1, (sum << 1) | (*s - '0')) :
*s == ' ' || *s == '_' ? test(s + 1, sum) : *s == ' ' || *s == '_' ? test(s + 1, sum) :
@ -44,22 +44,22 @@ namespace bit {
} }
//lowest(0b1110) == 0b0010 //lowest(0b1110) == 0b0010
constexpr inline auto lowest(const uintmax x) -> uintmax { constexpr inline auto lowest(const uintmax_t x) -> uintmax_t {
return x & -x; return x & -x;
} }
//clear_lowest(0b1110) == 0b1100 //clear_lowest(0b1110) == 0b1100
constexpr inline auto clearLowest(const uintmax x) -> uintmax { constexpr inline auto clearLowest(const uintmax_t x) -> uintmax_t {
return x & (x - 1); return x & (x - 1);
} }
//set_lowest(0b0101) == 0b0111 //set_lowest(0b0101) == 0b0111
constexpr inline auto setLowest(const uintmax x) -> uintmax { constexpr inline auto setLowest(const uintmax_t x) -> uintmax_t {
return x | (x + 1); return x | (x + 1);
} }
//count number of bits set in a byte //count number of bits set in a byte
inline auto count(uintmax x) -> uint { inline auto count(uintmax_t x) -> uint {
uint count = 0; uint count = 0;
do count += x & 1; while(x >>= 1); do count += x & 1; while(x >>= 1);
return count; return count;
@ -67,7 +67,7 @@ namespace bit {
//return index of the first bit set (or zero of no bits are set) //return index of the first bit set (or zero of no bits are set)
//first(0b1000) == 3 //first(0b1000) == 3
inline auto first(uintmax x) -> uint { inline auto first(uintmax_t x) -> uint {
uint first = 0; uint first = 0;
while(x) { if(x & 1) break; x >>= 1; first++; } while(x) { if(x & 1) break; x >>= 1; first++; }
return first; return first;
@ -75,7 +75,7 @@ namespace bit {
//round up to next highest single bit: //round up to next highest single bit:
//round(15) == 16, round(16) == 16, round(17) == 32 //round(15) == 16, round(16) == 16, round(17) == 32
inline auto round(uintmax x) -> uintmax { inline auto round(uintmax_t x) -> uintmax_t {
if((x & (x - 1)) == 0) return x; if((x & (x - 1)) == 0) return x;
while(x & (x - 1)) x &= x - 1; while(x & (x - 1)) x &= x - 1;
return x << 1; return x << 1;

View File

@ -30,9 +30,9 @@ struct Node {
auto set(const string& value) -> void { auto set(const string& value) -> void {
switch(type) { switch(type) {
case Type::Boolean: *(bool*)data = (value != "false"); break; case Type::Boolean: *(bool*)data = (value != "false"); break;
case Type::Integer: *(int*)data = integer(value); break; case Type::Integer: *(int*)data = toInteger(value); break;
case Type::Natural: *(uint*)data = natural(value); break; case Type::Natural: *(uint*)data = toNatural(value); break;
case Type::Double: *(double*)data = real(value); break; case Type::Double: *(double*)data = toReal(value); break;
case Type::String: *(string*)data = value; break; case Type::String: *(string*)data = value; break;
} }
} }

View File

@ -61,7 +61,7 @@ struct file : inode, varint {
return !(data.st_mode & S_IFDIR); return !(data.st_mode & S_IFDIR);
} }
static auto size(const string& filename) -> uintmax { static auto size(const string& filename) -> uintmax_t {
#if defined(API_POSIX) #if defined(API_POSIX)
struct stat data; struct stat data;
stat(filename, &data); stat(filename, &data);
@ -127,16 +127,16 @@ struct file : inode, varint {
return buffer[(file_offset++) & buffer_mask]; return buffer[(file_offset++) & buffer_mask];
} }
auto readl(uint length = 1) -> uintmax { auto readl(uint length = 1) -> uintmax_t {
uintmax data = 0; uintmax_t data = 0;
for(int i = 0; i < length; i++) { for(int i = 0; i < length; i++) {
data |= (uintmax)read() << (i << 3); data |= (uintmax_t)read() << (i << 3);
} }
return data; return data;
} }
auto readm(uint length = 1) -> uintmax { auto readm(uint length = 1) -> uintmax_t {
uintmax data = 0; uintmax_t data = 0;
while(length--) { while(length--) {
data <<= 8; data <<= 8;
data |= read(); data |= read();
@ -164,14 +164,14 @@ struct file : inode, varint {
if(file_offset > file_size) file_size = file_offset; if(file_offset > file_size) file_size = file_offset;
} }
auto writel(uintmax data, uint length = 1) -> void { auto writel(uintmax_t data, uint length = 1) -> void {
while(length--) { while(length--) {
write(data); write(data);
data >>= 8; data >>= 8;
} }
} }
auto writem(uintmax data, uint length = 1) -> void { auto writem(uintmax_t data, uint length = 1) -> void {
for(int i = length - 1; i >= 0; i--) { for(int i = length - 1; i >= 0; i--) {
write(data >> (i << 3)); write(data >> (i << 3));
} }
@ -200,7 +200,7 @@ struct file : inode, varint {
if(!fp) return; //file not open if(!fp) return; //file not open
buffer_flush(); buffer_flush();
intmax req_offset = file_offset; intmax_t req_offset = file_offset;
switch(index_) { switch(index_) {
case index::absolute: req_offset = offset; break; case index::absolute: req_offset = offset; break;
case index::relative: req_offset += offset; break; case index::relative: req_offset += offset; break;

View File

@ -94,7 +94,7 @@ auto Response::setHead() -> bool {
else if(response.ibeginsWith("HTTP/1.1 ")) response.itrimLeft("HTTP/1.1 ", 1L); else if(response.ibeginsWith("HTTP/1.1 ")) response.itrimLeft("HTTP/1.1 ", 1L);
else return false; else return false;
setResponseType(natural(response)); setResponseType(response.natural());
for(auto& header : headers) { for(auto& header : headers) {
if(header.beginsWith(" ") || header.beginsWith("\t")) continue; if(header.beginsWith(" ") || header.beginsWith("\t")) continue;

View File

@ -101,7 +101,7 @@ auto Role::download(signed fd, Message& message) -> bool {
if(chunk.endsWith("\r\n") || chunk.endsWith("\n")) { if(chunk.endsWith("\r\n") || chunk.endsWith("\n")) {
chunkReceived = true; chunkReceived = true;
chunkLength = hex(chunk); chunkLength = chunk.hex();
if(chunkLength == 0) break; if(chunkLength == 0) break;
chunk.reset(); chunk.reset();
} }

View File

@ -31,29 +31,29 @@ auto service::command(const string& name, const string& command) -> bool {
" stop : stop service if it is running\n" " stop : stop service if it is running\n"
" remove : remove semaphore lock if service crashed\n" " remove : remove semaphore lock if service crashed\n"
" {value} : send custom command to service\n" " {value} : send custom command to service\n"
"", format{name}), false; "", string_format{name}), false;
if(shared.open(name, 4096)) { if(shared.open(name, 4096)) {
if(command == "start") { if(command == "start") {
print("[{0}] already started\n", format{name}); print("[{0}] already started\n", string_format{name});
} else if(command == "status") { } else if(command == "status") {
print("[{0}] running\n", format{name}); print("[{0}] running\n", string_format{name});
} }
if(auto data = shared.acquire()) { if(auto data = shared.acquire()) {
if(command == "stop") print("[{0}] stopped\n", format{name}); if(command == "stop") print("[{0}] stopped\n", string_format{name});
memory::copy(data, command.data(), min(command.size(), 4096)); memory::copy(data, command.data(), min(command.size(), 4096));
shared.release(); shared.release();
} }
if(command == "remove") { if(command == "remove") {
shared.remove(); shared.remove();
print("[{0}] removed\n", format{name}); print("[{0}] removed\n", string_format{name});
} }
return false; return false;
} }
if(command == "start") { if(command == "start") {
if(shared.create(name, 4096)) { if(shared.create(name, 4096)) {
print("[{0}] started\n", format{name}); print("[{0}] started\n", string_format{name});
auto pid = fork(); auto pid = fork();
if(pid == 0) { if(pid == 0) {
signal(SIGHUP, SIG_IGN); signal(SIGHUP, SIG_IGN);
@ -63,13 +63,13 @@ auto service::command(const string& name, const string& command) -> bool {
} }
shared.close(); shared.close();
} else { } else {
print("[{0}] start failed ({1})\n", format{name, strerror(errno)}); print("[{0}] start failed ({1})\n", string_format{name, strerror(errno)});
} }
return false; return false;
} }
if(command == "status") { if(command == "status") {
print("[{0}] stopped\n", format{name}); print("[{0}] stopped\n", string_format{name});
return false; return false;
} }

View File

@ -79,15 +79,15 @@ template<uint Bits> struct Natural {
inline auto bit(uint index) -> Reference { return {*this, index, index}; } inline auto bit(uint index) -> Reference { return {*this, index, index}; }
inline auto byte(uint index) -> Reference { return {*this, index * 8 + 0, index * 8 + 7}; } inline auto byte(uint index) -> Reference { return {*this, index * 8 + 0, index * 8 + 7}; }
inline auto clamp(uint bits) -> uintmax { inline auto clamp(uint bits) -> uintmax_t {
const uintmax b = 1ull << (bits - 1); const uintmax_t b = 1ull << (bits - 1);
const uintmax m = b * 2 - 1; const uintmax_t m = b * 2 - 1;
return data < m ? data : m; return data < m ? data : m;
} }
inline auto clip(uint bits) -> uintmax { inline auto clip(uint bits) -> uintmax_t {
const uintmax b = 1ull << (bits - 1); const uintmax_t b = 1ull << (bits - 1);
const uintmax m = b * 2 - 1; const uintmax_t m = b * 2 - 1;
return data & m; return data & m;
} }
@ -161,15 +161,15 @@ template<uint Bits> struct Integer {
inline auto bit(uint index) -> Reference { return {*this, index, index}; } inline auto bit(uint index) -> Reference { return {*this, index, index}; }
inline auto byte(uint index) -> Reference { return {*this, index * 8 + 0, index * 8 + 7}; } inline auto byte(uint index) -> Reference { return {*this, index * 8 + 0, index * 8 + 7}; }
inline auto clamp(uint bits) -> intmax { inline auto clamp(uint bits) -> intmax_t {
const intmax b = 1ull << (bits - 1); const intmax_t b = 1ull << (bits - 1);
const intmax m = b - 1; const intmax_t m = b - 1;
return data > m ? m : data < -b ? -b : data; return data > m ? m : data < -b ? -b : data;
} }
inline auto clip(uint bits) -> intmax { inline auto clip(uint bits) -> intmax_t {
const uintmax b = 1ull << (bits - 1); const uintmax_t b = 1ull << (bits - 1);
const uintmax m = b * 2 - 1; const uintmax_t m = b * 2 - 1;
return ((data & m) ^ b) - b; return ((data & m) ^ b) - b;
} }
@ -185,8 +185,8 @@ template<uint Bits> struct Real {
using type = using type =
type_if<expression<Bits == 32>, float32_t, type_if<expression<Bits == 32>, float32_t,
type_if<expression<Bits == 64>, float64_t, type_if<expression<Bits == 64>, float64_t,
type_if<expression<Bits == 80>, float80_t, //type_if<expression<Bits == 80>, float80_t,
void>>>; void>>;
inline Real() : data(0.0) {} inline Real() : data(0.0) {}
template<typename T> inline Real(const T& value) : data((type)value) {} template<typename T> inline Real(const T& value) : data((type)value) {}
@ -215,9 +215,8 @@ private:
} }
using boolean = nall::Boolean; using boolean = nall::Boolean;
//note: these conflict with nall/atoi.hpp functions using integer = nall::Integer<sizeof( int) * 8>;
//using integer = nall::Integer<sizeof( int) * 8>; using natural = nall::Natural<sizeof(uint) * 8>;
//using natural = nall::Natural<sizeof(uint) * 8>;
using int1 = nall::Integer< 1>; using int1 = nall::Integer< 1>;
using int2 = nall::Integer< 2>; using int2 = nall::Integer< 2>;
@ -351,4 +350,4 @@ using uint64 = nall::Natural<64>;
using float32 = nall::Real<32>; using float32 = nall::Real<32>;
using float64 = nall::Real<64>; using float64 = nall::Real<64>;
using float80 = nall::Real<80>; //using float80 = nall::Real<80>;

View File

@ -63,10 +63,10 @@ struct serializer {
template<typename T> auto integer(T& value) -> serializer& { template<typename T> auto integer(T& value) -> serializer& {
enum { size = std::is_same<bool, T>::value ? 1 : sizeof(T) }; enum { size = std::is_same<bool, T>::value ? 1 : sizeof(T) };
if(_mode == Save) { if(_mode == Save) {
for(uint n = 0; n < size; n++) _data[_size++] = (uintmax)value >> (n << 3); for(uint n = 0; n < size; n++) _data[_size++] = (uintmax_t)value >> (n << 3);
} else if(_mode == Load) { } else if(_mode == Load) {
value = 0; value = 0;
for(uint n = 0; n < size; n++) value |= (uintmax)_data[_size++] << (n << 3); for(uint n = 0; n < size; n++) value |= (uintmax_t)_data[_size++] << (n << 3);
} else if(_mode == Size) { } else if(_mode == Size) {
_size += size; _size += size;
} }

View File

@ -33,7 +33,8 @@
using float32_t = float; using float32_t = float;
using float64_t = double; using float64_t = double;
using float80_t = long double; //note: long double size is not reliable across platforms
//using float80_t = long double;
static_assert(sizeof(int8_t) == 1, "int8_t is not of the correct size" ); static_assert(sizeof(int8_t) == 1, "int8_t is not of the correct size" );
static_assert(sizeof(int16_t) == 2, "int16_t is not of the correct size"); static_assert(sizeof(int16_t) == 2, "int16_t is not of the correct size");
@ -47,12 +48,6 @@ static_assert(sizeof(uint64_t) == 8, "int64_t is not of the correct size");
static_assert(sizeof(float) >= 4, "float32_t is not of the correct size"); static_assert(sizeof(float) >= 4, "float32_t is not of the correct size");
static_assert(sizeof(double) >= 8, "float64_t is not of the correct size"); static_assert(sizeof(double) >= 8, "float64_t is not of the correct size");
static_assert(sizeof(long double) >= 10, "float80_t is not of the correct size"); //static_assert(sizeof(long double) >= 10, "float80_t is not of the correct size");
using intmax = intmax_t;
using intptr = intptr_t;
using uintmax = uintmax_t;
using uintptr = uintptr_t;
using uint = unsigned int; using uint = unsigned int;

View File

@ -24,8 +24,12 @@
namespace nall { namespace nall {
struct string; struct string;
struct format; struct string_view;
struct lstring; struct string_vector;
struct string_format;
//legacy naming convention
using lstring = string_vector;
struct string_view { struct string_view {
inline string_view(); inline string_view();
@ -61,18 +65,19 @@ template<typename T> struct stringify;
//format.hpp //format.hpp
template<typename... P> inline auto print(P&&...) -> void; template<typename... P> inline auto print(P&&...) -> void;
template<typename... P> inline auto print(FILE*, P&&...) -> void; template<typename... P> inline auto print(FILE*, P&&...) -> void;
inline auto integer(intmax value, long precision = 0, char padchar = '0') -> string; template<typename T> inline auto numeral(T value, long precision = 0, char padchar = '0') -> string;
inline auto natural(uintmax value, long precision = 0, char padchar = '0') -> string; //inline auto integer(intmax_t value, long precision = 0, char padchar = '0') -> string;
inline auto hex(uintmax value, long precision = 0, char padchar = '0') -> string; //inline auto natural(uintmax_t value, long precision = 0, char padchar = '0') -> string;
inline auto octal(uintmax value, long precision = 0, char padchar = '0') -> string; inline auto hex(uintmax_t value, long precision = 0, char padchar = '0') -> string;
inline auto binary(uintmax value, long precision = 0, char padchar = '0') -> string; inline auto octal(uintmax_t value, long precision = 0, char padchar = '0') -> string;
inline auto binary(uintmax_t value, long precision = 0, char padchar = '0') -> string;
template<typename T> inline auto pointer(const T* value, long precision = 0) -> string; template<typename T> inline auto pointer(const T* value, long precision = 0) -> string;
inline auto pointer(uintptr value, long precision = 0) -> string; inline auto pointer(uintptr_t value, long precision = 0) -> string;
inline auto real(long double value) -> string; //inline auto real(long double value) -> string;
//match.hpp //match.hpp
inline auto tokenize(const char* s, const char* p) -> bool; inline auto tokenize(const char* s, const char* p) -> bool;
inline auto tokenize(lstring& list, const char* s, const char* p) -> bool; inline auto tokenize(string_vector& list, const char* s, const char* p) -> bool;
//path.hpp //path.hpp
inline auto pathname(string_view self) -> string; inline auto pathname(string_view self) -> string;
@ -85,10 +90,9 @@ inline auto suffixname(string_view self) -> string;
//utility.hpp //utility.hpp
inline auto slice(string_view self, int offset = 0, int length = -1) -> string; inline auto slice(string_view self, int offset = 0, int length = -1) -> string;
inline auto fromInteger(char* result, intmax_t value) -> char*;
inline auto integer(char* result, intmax value) -> char*; inline auto fromNatural(char* result, uintmax_t value) -> char*;
inline auto natural(char* result, uintmax value) -> char*; inline auto fromReal(char* str, long double value) -> uint;
inline auto real(char* str, long double value) -> uint;
struct string { struct string {
using type = string; using type = string;
@ -179,15 +183,16 @@ public:
auto end() const -> const char* { return &data()[size()]; } auto end() const -> const char* { return &data()[size()]; }
//atoi.hpp //atoi.hpp
inline auto integer() const -> intmax; inline auto integer() const -> intmax_t;
inline auto natural() const -> uintmax; inline auto natural() const -> uintmax_t;
inline auto hex() const -> uintmax_t;
inline auto real() const -> double; inline auto real() const -> double;
//core.hpp //core.hpp
inline auto operator[](int) const -> const char&; inline auto operator[](int) const -> const char&;
template<typename... P> inline auto assign(P&&...) -> type&; template<typename... P> inline auto assign(P&&...) -> type&;
template<typename T, typename... P> inline auto append(const T&, P&&...) -> type&; template<typename T, typename... P> inline auto append(const T&, P&&...) -> type&;
template<typename... P> inline auto append(const nall::format&, P&&...) -> type&; template<typename... P> inline auto append(const nall::string_format&, P&&...) -> type&;
inline auto append() -> type&; inline auto append() -> type&;
template<typename T> inline auto _append(const stringify<T>&) -> string&; template<typename T> inline auto _append(const stringify<T>&) -> string&;
inline auto length() const -> uint; inline auto length() const -> uint;
@ -209,7 +214,7 @@ public:
inline auto ifindFrom(int offset, string_view source) const -> maybe<uint>; inline auto ifindFrom(int offset, string_view source) const -> maybe<uint>;
//format.hpp //format.hpp
inline auto format(const nall::format& params) -> type&; inline auto format(const nall::string_format& params) -> type&;
//compare.hpp //compare.hpp
template<bool> inline static auto _compare(const char*, uint, const char*, uint) -> int; template<bool> inline static auto _compare(const char*, uint, const char*, uint) -> int;
@ -250,10 +255,10 @@ public:
inline auto iqreplace(string_view from, string_view to, long limit = LONG_MAX) -> type&; inline auto iqreplace(string_view from, string_view to, long limit = LONG_MAX) -> type&;
//split.hpp //split.hpp
inline auto split(string_view key, long limit = LONG_MAX) const -> lstring; inline auto split(string_view key, long limit = LONG_MAX) const -> string_vector;
inline auto isplit(string_view key, long limit = LONG_MAX) const -> lstring; inline auto isplit(string_view key, long limit = LONG_MAX) const -> string_vector;
inline auto qsplit(string_view key, long limit = LONG_MAX) const -> lstring; inline auto qsplit(string_view key, long limit = LONG_MAX) const -> string_vector;
inline auto iqsplit(string_view key, long limit = LONG_MAX) const -> lstring; inline auto iqsplit(string_view key, long limit = LONG_MAX) const -> string_vector;
//trim.hpp //trim.hpp
inline auto trim(string_view lhs, string_view rhs, long limit = LONG_MAX) -> type&; inline auto trim(string_view lhs, string_view rhs, long limit = LONG_MAX) -> type&;
@ -278,21 +283,21 @@ public:
inline auto size(int length, char fill = ' ') -> type&; inline auto size(int length, char fill = ' ') -> type&;
}; };
struct lstring : vector<string> { struct string_vector : vector<string> {
using type = lstring; using type = string_vector;
lstring(const lstring& source) { vector::operator=(source); } string_vector(const string_vector& source) { vector::operator=(source); }
lstring(lstring& source) { vector::operator=(source); } string_vector(string_vector& source) { vector::operator=(source); }
lstring(lstring&& source) { vector::operator=(move(source)); } string_vector(string_vector&& source) { vector::operator=(move(source)); }
template<typename... P> lstring(P&&... p) { append(forward<P>(p)...); } template<typename... P> string_vector(P&&... p) { append(forward<P>(p)...); }
//list.hpp //list.hpp
inline auto operator==(const lstring&) const -> bool; inline auto operator==(const string_vector&) const -> bool;
inline auto operator!=(const lstring&) const -> bool; inline auto operator!=(const string_vector&) const -> bool;
inline auto operator=(const lstring& source) -> type& { return vector::operator=(source), *this; } inline auto operator=(const string_vector& source) -> type& { return vector::operator=(source), *this; }
inline auto operator=(lstring& source) -> type& { return vector::operator=(source), *this; } inline auto operator=(string_vector& source) -> type& { return vector::operator=(source), *this; }
inline auto operator=(lstring&& source) -> type& { return vector::operator=(move(source)), *this; } inline auto operator=(string_vector&& source) -> type& { return vector::operator=(move(source)), *this; }
inline auto isort() -> type&; inline auto isort() -> type&;
@ -301,18 +306,18 @@ struct lstring : vector<string> {
inline auto find(string_view source) const -> maybe<uint>; inline auto find(string_view source) const -> maybe<uint>;
inline auto ifind(string_view source) const -> maybe<uint>; inline auto ifind(string_view source) const -> maybe<uint>;
inline auto match(string_view pattern) const -> lstring; inline auto match(string_view pattern) const -> string_vector;
inline auto merge(string_view separator) const -> string; inline auto merge(string_view separator) const -> string;
inline auto strip() -> type&; inline auto strip() -> type&;
//split.hpp //split.hpp
template<bool, bool> inline auto _split(string_view, string_view, long) -> lstring&; template<bool, bool> inline auto _split(string_view, string_view, long) -> type&;
}; };
struct format : vector<string> { struct string_format : vector<string> {
using type = format; using type = string_format;
template<typename... P> format(P&&... p) { reserve(sizeof...(p)); append(forward<P>(p)...); } template<typename... P> string_format(P&&... p) { reserve(sizeof...(p)); append(forward<P>(p)...); }
template<typename T, typename... P> inline auto append(const T&, P&&... p) -> type&; template<typename T, typename... P> inline auto append(const T&, P&&... p) -> type&;
inline auto append() -> type&; inline auto append() -> type&;
}; };

View File

@ -2,16 +2,20 @@
namespace nall { namespace nall {
auto string::integer() const -> intmax { auto string::integer() const -> intmax_t {
return nall::integer(data()); return toInteger(data());
} }
auto string::natural() const -> uintmax { auto string::natural() const -> uintmax_t {
return nall::natural(data()); return toNatural(data());
}
auto string::hex() const -> uintmax_t {
return toHex(data());
} }
auto string::real() const -> double { auto string::real() const -> double {
return nall::real(data()); return toReal(data());
} }
} }

View File

@ -33,42 +33,42 @@ template<> struct stringify<char> {
//signed integers //signed integers
template<> struct stringify<signed char> { template<> struct stringify<signed char> {
stringify(signed char source) { integer(_data, source); } stringify(signed char source) { fromInteger(_data, source); }
auto data() const -> const char* { return _data; } auto data() const -> const char* { return _data; }
auto size() const -> uint { return strlen(_data); } auto size() const -> uint { return strlen(_data); }
char _data[2 + sizeof(signed char) * 3]; char _data[2 + sizeof(signed char) * 3];
}; };
template<> struct stringify<signed short> { template<> struct stringify<signed short> {
stringify(signed short source) { integer(_data, source); } stringify(signed short source) { fromInteger(_data, source); }
auto data() const -> const char* { return _data; } auto data() const -> const char* { return _data; }
auto size() const -> uint { return strlen(_data); } auto size() const -> uint { return strlen(_data); }
char _data[2 + sizeof(signed short) * 3]; char _data[2 + sizeof(signed short) * 3];
}; };
template<> struct stringify<signed int> { template<> struct stringify<signed int> {
stringify(signed int source) { integer(_data, source); } stringify(signed int source) { fromInteger(_data, source); }
auto data() const -> const char* { return _data; } auto data() const -> const char* { return _data; }
auto size() const -> uint { return strlen(_data); } auto size() const -> uint { return strlen(_data); }
char _data[2 + sizeof(signed int) * 3]; char _data[2 + sizeof(signed int) * 3];
}; };
template<> struct stringify<signed long> { template<> struct stringify<signed long> {
stringify(signed long source) { integer(_data, source); } stringify(signed long source) { fromInteger(_data, source); }
auto data() const -> const char* { return _data; } auto data() const -> const char* { return _data; }
auto size() const -> uint { return strlen(_data); } auto size() const -> uint { return strlen(_data); }
char _data[2 + sizeof(signed long) * 3]; char _data[2 + sizeof(signed long) * 3];
}; };
template<> struct stringify<signed long long> { template<> struct stringify<signed long long> {
stringify(signed long long source) { integer(_data, source); } stringify(signed long long source) { fromInteger(_data, source); }
auto data() const -> const char* { return _data; } auto data() const -> const char* { return _data; }
auto size() const -> uint { return strlen(_data); } auto size() const -> uint { return strlen(_data); }
char _data[2 + sizeof(signed long long) * 3]; char _data[2 + sizeof(signed long long) * 3];
}; };
template<uint Bits> struct stringify<Integer<Bits>> { template<uint Bits> struct stringify<Integer<Bits>> {
stringify(Integer<Bits> source) { integer(_data, source); } stringify(Integer<Bits> source) { fromInteger(_data, source); }
auto data() const -> const char* { return _data; } auto data() const -> const char* { return _data; }
auto size() const -> uint { return strlen(_data); } auto size() const -> uint { return strlen(_data); }
char _data[2 + sizeof(int64_t) * 3]; char _data[2 + sizeof(int64_t) * 3];
@ -77,42 +77,42 @@ template<uint Bits> struct stringify<Integer<Bits>> {
//unsigned integers //unsigned integers
template<> struct stringify<unsigned char> { template<> struct stringify<unsigned char> {
stringify(unsigned char source) { natural(_data, source); } stringify(unsigned char source) { fromNatural(_data, source); }
auto data() const -> const char* { return _data; } auto data() const -> const char* { return _data; }
auto size() const -> uint { return strlen(_data); } auto size() const -> uint { return strlen(_data); }
char _data[1 + sizeof(unsigned char) * 3]; char _data[1 + sizeof(unsigned char) * 3];
}; };
template<> struct stringify<unsigned short> { template<> struct stringify<unsigned short> {
stringify(unsigned short source) { natural(_data, source); } stringify(unsigned short source) { fromNatural(_data, source); }
auto data() const -> const char* { return _data; } auto data() const -> const char* { return _data; }
auto size() const -> uint { return strlen(_data); } auto size() const -> uint { return strlen(_data); }
char _data[1 + sizeof(unsigned short) * 3]; char _data[1 + sizeof(unsigned short) * 3];
}; };
template<> struct stringify<unsigned int> { template<> struct stringify<unsigned int> {
stringify(unsigned int source) { natural(_data, source); } stringify(unsigned int source) { fromNatural(_data, source); }
auto data() const -> const char* { return _data; } auto data() const -> const char* { return _data; }
auto size() const -> uint { return strlen(_data); } auto size() const -> uint { return strlen(_data); }
char _data[1 + sizeof(unsigned int) * 3]; char _data[1 + sizeof(unsigned int) * 3];
}; };
template<> struct stringify<unsigned long> { template<> struct stringify<unsigned long> {
stringify(unsigned long source) { natural(_data, source); } stringify(unsigned long source) { fromNatural(_data, source); }
auto data() const -> const char* { return _data; } auto data() const -> const char* { return _data; }
auto size() const -> uint { return strlen(_data); } auto size() const -> uint { return strlen(_data); }
char _data[1 + sizeof(unsigned long) * 3]; char _data[1 + sizeof(unsigned long) * 3];
}; };
template<> struct stringify<unsigned long long> { template<> struct stringify<unsigned long long> {
stringify(unsigned long long source) { natural(_data, source); } stringify(unsigned long long source) { fromNatural(_data, source); }
auto data() const -> const char* { return _data; } auto data() const -> const char* { return _data; }
auto size() const -> uint { return strlen(_data); } auto size() const -> uint { return strlen(_data); }
char _data[1 + sizeof(unsigned long long) * 3]; char _data[1 + sizeof(unsigned long long) * 3];
}; };
template<uint Bits> struct stringify<Natural<Bits>> { template<uint Bits> struct stringify<Natural<Bits>> {
stringify(Natural<Bits> source) { natural(_data, source); } stringify(Natural<Bits> source) { fromNatural(_data, source); }
auto data() const -> const char* { return _data; } auto data() const -> const char* { return _data; }
auto size() const -> uint { return strlen(_data); } auto size() const -> uint { return strlen(_data); }
char _data[1 + sizeof(uint64_t) * 3]; char _data[1 + sizeof(uint64_t) * 3];
@ -121,28 +121,28 @@ template<uint Bits> struct stringify<Natural<Bits>> {
//floating-point //floating-point
template<> struct stringify<float> { template<> struct stringify<float> {
stringify(float source) { real(_data, source); } stringify(float source) { fromReal(_data, source); }
auto data() const -> const char* { return _data; } auto data() const -> const char* { return _data; }
auto size() const -> uint { return strlen(_data); } auto size() const -> uint { return strlen(_data); }
char _data[256]; char _data[256];
}; };
template<> struct stringify<double> { template<> struct stringify<double> {
stringify(double source) { real(_data, source); } stringify(double source) { fromReal(_data, source); }
auto data() const -> const char* { return _data; } auto data() const -> const char* { return _data; }
auto size() const -> uint { return strlen(_data); } auto size() const -> uint { return strlen(_data); }
char _data[256]; char _data[256];
}; };
template<> struct stringify<long double> { template<> struct stringify<long double> {
stringify(long double source) { real(_data, source); } stringify(long double source) { fromReal(_data, source); }
auto data() const -> const char* { return _data; } auto data() const -> const char* { return _data; }
auto size() const -> uint { return strlen(_data); } auto size() const -> uint { return strlen(_data); }
char _data[256]; char _data[256];
}; };
template<uint Bits> struct stringify<Real<Bits>> { template<uint Bits> struct stringify<Real<Bits>> {
stringify(Real<Bits> source) { real(_data, source); } stringify(Real<Bits> source) { fromReal(_data, source); }
auto data() const -> const char* { return _data; } auto data() const -> const char* { return _data; }
auto size() const -> uint { return strlen(_data); } auto size() const -> uint { return strlen(_data); }
char _data[256]; char _data[256];

View File

@ -30,7 +30,7 @@ template<typename T, typename... P> auto string::append(const T& value, P&&... p
return append(forward<P>(p)...); return append(forward<P>(p)...);
} }
template<typename... P> auto string::append(const nall::format& value, P&&... p) -> string& { template<typename... P> auto string::append(const nall::string_format& value, P&&... p) -> string& {
format(value); format(value);
return append(forward<P>(p)...); return append(forward<P>(p)...);
} }

View File

@ -6,9 +6,9 @@ auto string::date(time_t timestamp) -> string {
if(timestamp == 0) timestamp = ::time(nullptr); if(timestamp == 0) timestamp = ::time(nullptr);
tm* info = localtime(&timestamp); tm* info = localtime(&timestamp);
return { return {
nall::natural(1900 + info->tm_year, 4L), "-", numeral(1900 + info->tm_year, 4L), "-",
nall::natural(1 + info->tm_mon, 2L), "-", numeral(1 + info->tm_mon, 2L), "-",
nall::natural(info->tm_mday, 2L) numeral(info->tm_mday, 2L)
}; };
} }
@ -16,9 +16,9 @@ auto string::time(time_t timestamp) -> string {
if(timestamp == 0) timestamp = ::time(nullptr); if(timestamp == 0) timestamp = ::time(nullptr);
tm* info = localtime(&timestamp); tm* info = localtime(&timestamp);
return { return {
nall::natural(info->tm_hour, 2L), ":", numeral(info->tm_hour, 2L), ":",
nall::natural(info->tm_min, 2L), ":", numeral(info->tm_min, 2L), ":",
nall::natural(info->tm_sec, 2L) numeral(info->tm_sec, 2L)
}; };
} }

View File

@ -37,7 +37,7 @@ inline auto evaluateExpression(Node* node) -> string {
} }
inline auto evaluateInteger(Node* node) -> int64_t { inline auto evaluateInteger(Node* node) -> int64_t {
if(node->type == Node::Type::Literal) return nall::integer(node->literal); if(node->type == Node::Type::Literal) return toInteger(node->literal);
#define p(n) evaluateInteger(node->link[n]) #define p(n) evaluateInteger(node->link[n])
switch(node->type) { switch(node->type) {
@ -99,7 +99,7 @@ inline auto integer(const string& expression) -> maybe<int64_t> {
} }
inline auto evaluateReal(Node* node) -> long double { inline auto evaluateReal(Node* node) -> long double {
if(node->type == Node::Type::Literal) return nall::real(node->literal); if(node->type == Node::Type::Literal) return toReal(node->literal);
#define p(n) evaluateReal(node->link[n]) #define p(n) evaluateReal(node->link[n])
switch(node->type) { switch(node->type) {

View File

@ -5,7 +5,7 @@ namespace nall {
//nall::format is a vector<string> of parameters that can be applied to a string //nall::format is a vector<string> of parameters that can be applied to a string
//each {#} token will be replaced with its appropriate format parameter //each {#} token will be replaced with its appropriate format parameter
auto string::format(const nall::format& params) -> type& { auto string::format(const nall::string_format& params) -> type& {
auto size = (int)this->size(); auto size = (int)this->size();
auto data = (char*)memory::allocate(size); auto data = (char*)memory::allocate(size);
memory::copy(data, this->data(), size); memory::copy(data, this->data(), size);
@ -32,7 +32,7 @@ auto string::format(const nall::format& params) -> type& {
}; };
if(!isNumeric(&data[x + 1], &data[y - 1])) { x++; continue; } if(!isNumeric(&data[x + 1], &data[y - 1])) { x++; continue; }
uint index = nall::natural(&data[x + 1]); uint index = toNatural(&data[x + 1]);
if(index >= params.size()) { x++; continue; } if(index >= params.size()) { x++; continue; }
uint sourceSize = y - x; uint sourceSize = y - x;
@ -59,12 +59,12 @@ auto string::format(const nall::format& params) -> type& {
return *this; return *this;
} }
template<typename T, typename... P> auto format::append(const T& value, P&&... p) -> format& { template<typename T, typename... P> auto string_format::append(const T& value, P&&... p) -> string_format& {
vector<string>::append(value); vector<string>::append(value);
return append(forward<P>(p)...); return append(forward<P>(p)...);
} }
auto format::append() -> format& { auto string_format::append() -> string_format& {
return *this; return *this;
} }
@ -78,9 +78,10 @@ template<typename... P> auto print(FILE* fp, P&&... p) -> void {
fwrite(s.data(), 1, s.size(), fp); fwrite(s.data(), 1, s.size(), fp);
} }
auto integer(intmax value, long precision, char padchar) -> string { /*
auto integer(intmax_t value, long precision, char padchar) -> string {
string buffer; string buffer;
buffer.resize(1 + sizeof(intmax) * 3); buffer.resize(1 + sizeof(intmax_t) * 3);
char* p = buffer.get(); char* p = buffer.get();
bool negative = value < 0; bool negative = value < 0;
@ -97,9 +98,9 @@ auto integer(intmax value, long precision, char padchar) -> string {
return buffer; return buffer;
} }
auto natural(uintmax value, long precision, char padchar) -> string { auto natural(uintmax_t value, long precision, char padchar) -> string {
string buffer; string buffer;
buffer.resize(sizeof(uintmax) * 3); buffer.resize(sizeof(uintmax_t) * 3);
char* p = buffer.get(); char* p = buffer.get();
uint size = 0; uint size = 0;
@ -112,10 +113,17 @@ auto natural(uintmax value, long precision, char padchar) -> string {
if(precision) buffer.size(precision, padchar); if(precision) buffer.size(precision, padchar);
return buffer; return buffer;
} }
*/
auto hex(uintmax value, long precision, char padchar) -> string { template<typename T> auto numeral(T value, long precision, char padchar) -> string {
string buffer{value};
if(precision) buffer.size(precision, padchar);
return buffer;
}
auto hex(uintmax_t value, long precision, char padchar) -> string {
string buffer; string buffer;
buffer.resize(sizeof(uintmax) * 2); buffer.resize(sizeof(uintmax_t) * 2);
char* p = buffer.get(); char* p = buffer.get();
uint size = 0; uint size = 0;
@ -130,9 +138,9 @@ auto hex(uintmax value, long precision, char padchar) -> string {
return buffer; return buffer;
} }
auto octal(uintmax value, long precision, char padchar) -> string { auto octal(uintmax_t value, long precision, char padchar) -> string {
string buffer; string buffer;
buffer.resize(sizeof(uintmax) * 3); buffer.resize(sizeof(uintmax_t) * 3);
char* p = buffer.get(); char* p = buffer.get();
uint size = 0; uint size = 0;
@ -146,9 +154,9 @@ auto octal(uintmax value, long precision, char padchar) -> string {
return buffer; return buffer;
} }
auto binary(uintmax value, long precision, char padchar) -> string { auto binary(uintmax_t value, long precision, char padchar) -> string {
string buffer; string buffer;
buffer.resize(sizeof(uintmax) * 8); buffer.resize(sizeof(uintmax_t) * 8);
char* p = buffer.get(); char* p = buffer.get();
uint size = 0; uint size = 0;
@ -164,19 +172,21 @@ auto binary(uintmax value, long precision, char padchar) -> string {
template<typename T> auto pointer(const T* value, long precision) -> string { template<typename T> auto pointer(const T* value, long precision) -> string {
if(value == nullptr) return "(nullptr)"; if(value == nullptr) return "(nullptr)";
return {"0x", hex((uintptr)value, precision)}; return {"0x", hex((uintptr_t)value, precision)};
} }
auto pointer(uintptr value, long precision) -> string { auto pointer(uintptr_t value, long precision) -> string {
if(value == 0) return "(nullptr)"; if(value == 0) return "(nullptr)";
return {"0x", hex(value, precision)}; return {"0x", hex(value, precision)};
} }
/*
auto real(long double value) -> string { auto real(long double value) -> string {
string temp; string temp;
temp.resize(real(nullptr, value)); temp.resize(fromReal(nullptr, value));
real(temp.get(), value); fromReal(temp.get(), value);
return temp; return temp;
} }
*/
} }

View File

@ -2,7 +2,7 @@
namespace nall { namespace nall {
auto lstring::operator==(const lstring& source) const -> bool { auto string_vector::operator==(const string_vector& source) const -> bool {
if(this == &source) return true; if(this == &source) return true;
if(size() != source.size()) return false; if(size() != source.size()) return false;
for(uint n = 0; n < size(); n++) { for(uint n = 0; n < size(); n++) {
@ -11,50 +11,50 @@ auto lstring::operator==(const lstring& source) const -> bool {
return true; return true;
} }
auto lstring::operator!=(const lstring& source) const -> bool { auto string_vector::operator!=(const string_vector& source) const -> bool {
return !operator==(source); return !operator==(source);
} }
auto lstring::isort() -> lstring& { auto string_vector::isort() -> type& {
sort([](const string& x, const string& y) { sort([](const string& x, const string& y) {
return memory::icompare(x.data(), x.size(), y.data(), y.size()) < 0; return memory::icompare(x.data(), x.size(), y.data(), y.size()) < 0;
}); });
return *this; return *this;
} }
template<typename... P> auto lstring::append(const string& data, P&&... p) -> lstring& { template<typename... P> auto string_vector::append(const string& data, P&&... p) -> type& {
vector::append(data); vector::append(data);
append(forward<P>(p)...); append(forward<P>(p)...);
return *this; return *this;
} }
auto lstring::append() -> lstring& { auto string_vector::append() -> type& {
return *this; return *this;
} }
auto lstring::find(string_view source) const -> maybe<uint> { auto string_vector::find(string_view source) const -> maybe<uint> {
for(uint n = 0; n < size(); n++) { for(uint n = 0; n < size(); n++) {
if(operator[](n).equals(source)) return n; if(operator[](n).equals(source)) return n;
} }
return nothing; return nothing;
} }
auto lstring::ifind(string_view source) const -> maybe<uint> { auto string_vector::ifind(string_view source) const -> maybe<uint> {
for(uint n = 0; n < size(); n++) { for(uint n = 0; n < size(); n++) {
if(operator[](n).iequals(source)) return n; if(operator[](n).iequals(source)) return n;
} }
return nothing; return nothing;
} }
auto lstring::match(string_view pattern) const -> lstring { auto string_vector::match(string_view pattern) const -> type {
lstring result; string_vector result;
for(uint n = 0; n < size(); n++) { for(uint n = 0; n < size(); n++) {
if(operator[](n).match(pattern)) result.append(operator[](n)); if(operator[](n).match(pattern)) result.append(operator[](n));
} }
return result; return result;
} }
auto lstring::merge(string_view separator) const -> string { auto string_vector::merge(string_view separator) const -> string {
string output; string output;
for(uint n = 0; n < size(); n++) { for(uint n = 0; n < size(); n++) {
output.append(operator[](n)); output.append(operator[](n));
@ -63,7 +63,7 @@ auto lstring::merge(string_view separator) const -> string {
return output; return output;
} }
auto lstring::strip() -> lstring& { auto string_vector::strip() -> type& {
for(uint n = 0; n < size(); n++) { for(uint n = 0; n < size(); n++) {
operator[](n).strip(); operator[](n).strip();
} }

View File

@ -59,8 +59,8 @@ struct Node {
auto text() const -> string { return value().strip(); } auto text() const -> string { return value().strip(); }
auto boolean() const -> bool { return text() == "true"; } auto boolean() const -> bool { return text() == "true"; }
auto integer() const -> intmax { return text().integer(); } auto integer() const -> intmax_t { return text().integer(); }
auto natural() const -> uintmax { return text().natural(); } auto natural() const -> uintmax_t { return text().natural(); }
auto real() const -> double { return text().real(); } auto real() const -> double { return text().real(); }
auto setName(const string& name = "") -> Node& { shared->_name = name; return *this; } auto setName(const string& name = "") -> Node& { shared->_name = name; return *this; }

View File

@ -68,7 +68,7 @@ auto tokenize(const char* s, const char* p) -> bool {
return !*p; return !*p;
} }
auto tokenize(lstring& list, const char* s, const char* p) -> bool { auto tokenize(string_vector& list, const char* s, const char* p) -> bool {
while(*s) { while(*s) {
if(*p == '*') { if(*p == '*') {
const char* b = s; const char* b = s;

View File

@ -3,7 +3,7 @@
namespace nall { namespace nall {
template<bool Insensitive, bool Quoted> template<bool Insensitive, bool Quoted>
auto lstring::_split(string_view source, string_view find, long limit) -> lstring& { auto string_vector::_split(string_view source, string_view find, long limit) -> string_vector& {
reset(); reset();
if(limit <= 0 || find.size() == 0) return *this; if(limit <= 0 || find.size() == 0) return *this;
@ -33,9 +33,9 @@ auto lstring::_split(string_view source, string_view find, long limit) -> lstrin
return *this; return *this;
} }
auto string::split(string_view on, long limit) const -> lstring { return lstring()._split<0, 0>(*this, on, limit); } auto string::split(string_view on, long limit) const -> string_vector { return string_vector()._split<0, 0>(*this, on, limit); }
auto string::isplit(string_view on, long limit) const -> lstring { return lstring()._split<1, 0>(*this, on, limit); } auto string::isplit(string_view on, long limit) const -> string_vector { return string_vector()._split<1, 0>(*this, on, limit); }
auto string::qsplit(string_view on, long limit) const -> lstring { return lstring()._split<0, 1>(*this, on, limit); } auto string::qsplit(string_view on, long limit) const -> string_vector { return string_vector()._split<0, 1>(*this, on, limit); }
auto string::iqsplit(string_view on, long limit) const -> lstring { return lstring()._split<1, 1>(*this, on, limit); } auto string::iqsplit(string_view on, long limit) const -> string_vector { return string_vector()._split<1, 1>(*this, on, limit); }
} }

View File

@ -92,7 +92,7 @@ auto slice(string_view self, int offset, int length) -> string {
return result; return result;
} }
auto integer(char* result, intmax value) -> char* { auto fromInteger(char* result, intmax_t value) -> char* {
bool negative = value < 0; bool negative = value < 0;
if(negative) value = -value; if(negative) value = -value;
@ -111,7 +111,7 @@ auto integer(char* result, intmax value) -> char* {
return result; return result;
} }
auto natural(char* result, uintmax value) -> char* { auto fromNatural(char* result, uintmax_t value) -> char* {
char buffer[64]; char buffer[64];
uint size = 0; uint size = 0;
@ -129,7 +129,7 @@ auto natural(char* result, uintmax value) -> char* {
//using sprintf is certainly not the most ideal method to convert //using sprintf is certainly not the most ideal method to convert
//a double to a string ... but attempting to parse a double by //a double to a string ... but attempting to parse a double by
//hand, digit-by-digit, results in subtle rounding errors. //hand, digit-by-digit, results in subtle rounding errors.
auto real(char* result, long double value) -> uint { auto fromReal(char* result, long double value) -> uint {
char buffer[256]; char buffer[256];
#ifdef _WIN32 #ifdef _WIN32
//Windows C-runtime does not support long double via sprintf() //Windows C-runtime does not support long double via sprintf()

View File

@ -19,13 +19,13 @@ namespace nall {
struct thread { struct thread {
inline auto join() -> void; inline auto join() -> void;
static inline auto create(const function<void (uintptr)>& callback, uintptr parameter = 0, uint stacksize = 0) -> thread; static inline auto create(const function<void (uintptr_t)>& callback, uintptr_t parameter = 0, uint stacksize = 0) -> thread;
static inline auto detach() -> void; static inline auto detach() -> void;
static inline auto exit() -> void; static inline auto exit() -> void;
struct context { struct context {
function<auto (uintptr) -> void> callback; function<auto (uintptr_t) -> void> callback;
uintptr parameter = 0; uintptr_t parameter = 0;
}; };
private: private:
@ -43,7 +43,7 @@ auto thread::join() -> void {
pthread_join(handle, nullptr); pthread_join(handle, nullptr);
} }
auto thread::create(const function<void (uintptr)>& callback, uintptr parameter, uint stacksize) -> thread { auto thread::create(const function<void (uintptr_t)>& callback, uintptr_t parameter, uint stacksize) -> thread {
thread instance; thread instance;
auto context = new thread::context; auto context = new thread::context;
@ -76,13 +76,13 @@ struct thread {
inline ~thread(); inline ~thread();
inline auto join() -> void; inline auto join() -> void;
static inline auto create(const function<void (uintptr)>& callback, uintptr parameter = 0, uint stacksize = 0) -> thread; static inline auto create(const function<void (uintptr_t)>& callback, uintptr_t parameter = 0, uint stacksize = 0) -> thread;
static inline auto detach() -> void; static inline auto detach() -> void;
static inline auto exit() -> void; static inline auto exit() -> void;
struct context { struct context {
function<auto (uintptr) -> void> callback; function<auto (uintptr_t) -> void> callback;
uintptr parameter = 0; uintptr_t parameter = 0;
}; };
private: private:
@ -111,7 +111,7 @@ auto thread::join() -> void {
} }
} }
auto thread::create(const function<void (uintptr)>& callback, uintptr parameter, uint stacksize) -> thread { auto thread::create(const function<void (uintptr_t)>& callback, uintptr_t parameter, uint stacksize) -> thread {
thread instance; thread instance;
auto context = new thread::context; auto context = new thread::context;

View File

@ -10,8 +10,8 @@ struct varint {
virtual auto read() -> uint8_t = 0; virtual auto read() -> uint8_t = 0;
virtual auto write(uint8_t) -> void = 0; virtual auto write(uint8_t) -> void = 0;
auto readvu() -> uintmax { auto readvu() -> uintmax_t {
uintmax data = 0, shift = 1; uintmax_t data = 0, shift = 1;
while(true) { while(true) {
uint8_t x = read(); uint8_t x = read();
data += (x & 0x7f) * shift; data += (x & 0x7f) * shift;
@ -22,15 +22,15 @@ struct varint {
return data; return data;
} }
auto readvs() -> intmax { auto readvs() -> intmax_t {
uintmax data = readvu(); uintmax_t data = readvu();
bool negate = data & 1; bool negate = data & 1;
data >>= 1; data >>= 1;
if(negate) data = ~data; if(negate) data = ~data;
return data; return data;
} }
auto writevu(uintmax data) -> void { auto writevu(uintmax_t data) -> void {
while(true) { while(true) {
uint8_t x = data & 0x7f; uint8_t x = data & 0x7f;
data >>= 7; data >>= 7;
@ -40,7 +40,7 @@ struct varint {
} }
} }
auto writevs(intmax data) -> void { auto writevs(intmax_t data) -> void {
bool negate = data < 0; bool negate = data < 0;
if(negate) data = ~data; if(negate) data = ~data;
data = (data << 1) | negate; data = (data << 1) | negate;

View File

@ -11,15 +11,15 @@ struct file : vfs::file {
return instance; return instance;
} }
auto size() const -> uintmax override { auto size() const -> uintmax_t override {
return _fp.size(); return _fp.size();
} }
auto offset() const -> uintmax override { auto offset() const -> uintmax_t override {
return _fp.offset(); return _fp.offset();
} }
auto seek(intmax offset_, index index_) -> void override { auto seek(intmax_t offset_, index index_) -> void override {
_fp.seek(offset_, (nall::file::index)index_); _fp.seek(offset_, (nall::file::index)index_);
} }

View File

@ -5,18 +5,18 @@ namespace nall { namespace vfs { namespace memory {
struct file : vfs::file { struct file : vfs::file {
~file() { delete[] _data; } ~file() { delete[] _data; }
static auto open(const uint8_t* data, uintmax size) -> vfs::shared::file { static auto open(const uint8_t* data, uintmax_t size) -> vfs::shared::file {
auto instance = shared_pointer<file>{new file}; auto instance = shared_pointer<file>{new file};
instance->_open(data, size); instance->_open(data, size);
return instance; return instance;
} }
auto size() const -> uintmax override { return _size; } auto size() const -> uintmax_t override { return _size; }
auto offset() const -> uintmax override { return _offset; } auto offset() const -> uintmax_t override { return _offset; }
auto seek(intmax offset, index mode) -> void override { auto seek(intmax_t offset, index mode) -> void override {
if(mode == index::absolute) _offset = (uintmax)offset; if(mode == index::absolute) _offset = (uintmax_t)offset;
if(mode == index::relative) _offset += (intmax)offset; if(mode == index::relative) _offset += (intmax_t)offset;
} }
auto read() -> uint8_t override { auto read() -> uint8_t override {
@ -34,15 +34,15 @@ private:
file(const file&) = delete; file(const file&) = delete;
auto operator=(const file&) -> file& = delete; auto operator=(const file&) -> file& = delete;
auto _open(const uint8_t* data, uintmax size) -> void { auto _open(const uint8_t* data, uintmax_t size) -> void {
_size = size; _size = size;
_data = new uint8_t[size]; _data = new uint8_t[size];
nall::memory::copy(_data, data, size); nall::memory::copy(_data, data, size);
} }
uint8_t* _data = nullptr; uint8_t* _data = nullptr;
uintmax _size = 0; uintmax_t _size = 0;
uintmax _offset = 0; uintmax_t _offset = 0;
}; };
}}} }}}

View File

@ -11,10 +11,10 @@ struct file {
virtual ~file() = default; virtual ~file() = default;
virtual auto size() const -> uintmax = 0; virtual auto size() const -> uintmax_t = 0;
virtual auto offset() const -> uintmax = 0; virtual auto offset() const -> uintmax_t = 0;
virtual auto seek(intmax offset, index = index::absolute) -> void = 0; virtual auto seek(intmax_t offset, index = index::absolute) -> void = 0;
virtual auto read() -> uint8_t = 0; virtual auto read() -> uint8_t = 0;
virtual auto write(uint8_t data) -> void = 0; virtual auto write(uint8_t data) -> void = 0;
virtual auto flush() -> void {} virtual auto flush() -> void {}
@ -23,19 +23,19 @@ struct file {
return offset() >= size(); return offset() >= size();
} }
auto read(void* vdata, uintmax bytes) -> void { auto read(void* vdata, uintmax_t bytes) -> void {
auto data = (uint8_t*)vdata; auto data = (uint8_t*)vdata;
while(bytes--) *data++ = read(); while(bytes--) *data++ = read();
} }
auto readl(uint bytes) -> uintmax { auto readl(uint bytes) -> uintmax_t {
uintmax data = 0; uintmax_t data = 0;
for(auto n : range(bytes)) data |= (uintmax)read() << n * 8; for(auto n : range(bytes)) data |= (uintmax_t)read() << n * 8;
return data; return data;
} }
auto readm(uint bytes) -> uintmax { auto readm(uint bytes) -> uintmax_t {
uintmax data = 0; uintmax_t data = 0;
for(auto n : range(bytes)) data = data << 8 | read(); for(auto n : range(bytes)) data = data << 8 | read();
return data; return data;
} }
@ -47,16 +47,16 @@ struct file {
return s; return s;
} }
auto write(const void* vdata, uintmax bytes) -> void { auto write(const void* vdata, uintmax_t bytes) -> void {
auto data = (const uint8_t*)vdata; auto data = (const uint8_t*)vdata;
while(bytes--) write(*data++); while(bytes--) write(*data++);
} }
auto writel(uintmax data, uint bytes) -> void { auto writel(uintmax_t data, uint bytes) -> void {
for(auto n : range(bytes)) write(data), data >>= 8; for(auto n : range(bytes)) write(data), data >>= 8;
} }
auto writem(uintmax data, uint bytes) -> void { auto writem(uintmax_t data, uint bytes) -> void {
for(auto n : rrange(bytes)) write(data >> n * 8); for(auto n : rrange(bytes)) write(data >> n * 8);
} }

View File

@ -14,7 +14,7 @@ struct InputXlib : Input {
~InputXlib() { term(); } ~InputXlib() { term(); }
struct Settings { struct Settings {
uintptr handle = 0; uintptr_t handle = 0;
} settings; } settings;
auto cap(const string& name) -> bool { auto cap(const string& name) -> bool {
@ -29,8 +29,8 @@ struct InputXlib : Input {
} }
auto set(const string& name, const any& value) -> bool { auto set(const string& name, const any& value) -> bool {
if(name == Input::Handle && value.is<uintptr>()) { if(name == Input::Handle && value.is<uintptr_t>()) {
settings.handle = value.get<uintptr>(); settings.handle = value.get<uintptr_t>();
return true; return true;
} }

View File

@ -32,15 +32,15 @@ struct VideoCGL : Video, OpenGL {
} }
auto get(const string& name) -> any { auto get(const string& name) -> any {
if(name == Video::Handle) return (uintptr)settings.handle; if(name == Video::Handle) return (uintptr_t)settings.handle;
if(name == Video::Synchronize) return settings.synchronize; if(name == Video::Synchronize) return settings.synchronize;
if(name == Video::Filter) return settings.filter; if(name == Video::Filter) return settings.filter;
return {}; return {};
} }
auto set(const string& name, const any& value) -> bool { auto set(const string& name, const any& value) -> bool {
if(name == Video::Handle && value.is<uintptr>()) { if(name == Video::Handle && value.is<uintptr_t>()) {
settings.handle = (NSView*)value.get<uintptr>(); settings.handle = (NSView*)value.get<uintptr_t>();
return true; return true;
} }

View File

@ -28,11 +28,11 @@ auto OpenGL::shader(const string& pathname) -> void {
for(auto node : document["output"]) { for(auto node : document["output"]) {
string text = node.text(); string text = node.text();
if(node.name() == "width") { if(node.name() == "width") {
if(text.endsWith("%")) relativeWidth = real(text.trimRight("%", 1L)) / 100.0; if(text.endsWith("%")) relativeWidth = toReal(text.trimRight("%", 1L)) / 100.0;
else absoluteWidth = text.natural(); else absoluteWidth = text.natural();
} }
if(node.name() == "height") { if(node.name() == "height") {
if(text.endsWith("%")) relativeHeight = real(text.trimRight("%", 1L)) / 100.0; if(text.endsWith("%")) relativeHeight = toReal(text.trimRight("%", 1L)) / 100.0;
else absoluteHeight = text.natural(); else absoluteHeight = text.natural();
} }
} }

View File

@ -4,9 +4,9 @@ auto OpenGLProgram::bind(OpenGL* instance, const Markup::Node& node, const strin
modulo = glrModulo(node["modulo"].integer()); modulo = glrModulo(node["modulo"].integer());
string w = node["width"].text(), h = node["height"].text(); string w = node["width"].text(), h = node["height"].text();
if(w.endsWith("%")) relativeWidth = real(w.trimRight("%", 1L)) / 100.0; if(w.endsWith("%")) relativeWidth = toReal(w.trimRight("%", 1L)) / 100.0;
else absoluteWidth = w.natural(); else absoluteWidth = w.natural();
if(h.endsWith("%")) relativeHeight = real(h.trimRight("%", 1L)) / 100.0; if(h.endsWith("%")) relativeHeight = toReal(h.trimRight("%", 1L)) / 100.0;
else absoluteHeight = h.natural(); else absoluteHeight = h.natural();
format = glrFormat(node["format"].text()); format = glrFormat(node["format"].text());

View File

@ -30,15 +30,15 @@ struct VideoWGL : Video, OpenGL {
} }
auto get(const string& name) -> any { auto get(const string& name) -> any {
if(name == Video::Handle) return (uintptr)settings.handle; if(name == Video::Handle) return (uintptr_t)settings.handle;
if(name == Video::Synchronize) return settings.synchronize; if(name == Video::Synchronize) return settings.synchronize;
if(name == Video::Filter) return settings.filter; if(name == Video::Filter) return settings.filter;
return {}; return {};
} }
auto set(const string& name, const any& value) -> bool { auto set(const string& name, const any& value) -> bool {
if(name == Video::Handle && value.is<uintptr>()) { if(name == Video::Handle && value.is<uintptr_t>()) {
settings.handle = (HWND)value.get<uintptr>(); settings.handle = (HWND)value.get<uintptr_t>();
return true; return true;
} }