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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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