mirror of
https://github.com/libretro/bsnes-libretro-cplusplus98.git
synced 2025-04-12 07:07:02 +00:00
Start on hardcore translation ...
This commit is contained in:
parent
0df97c5157
commit
e1912f77cd
@ -13,8 +13,10 @@ public:
|
||||
virtual void loadCartridge(const string &markup, const uint8_t *data, unsigned size);
|
||||
virtual void unloadCartridge();
|
||||
|
||||
enum class Memory : unsigned {
|
||||
RAM
|
||||
struct Memory {
|
||||
enum e {
|
||||
RAM
|
||||
} i;
|
||||
};
|
||||
|
||||
virtual unsigned memorySize(Memory);
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <nall/C++98.hpp>
|
||||
#include <nall/utility.hpp>
|
||||
|
||||
#include <nall/array.hpp>
|
||||
#include <nall/string/base.hpp>
|
||||
#include <nall/string/bsv.hpp>
|
||||
#include <nall/string/core.hpp>
|
||||
@ -22,6 +23,9 @@
|
||||
#include <nall/string/variadic.hpp>
|
||||
#include <nall/string/xml.hpp>
|
||||
|
||||
#include <nall/string/bml.hpp>
|
||||
#include <nall/string/cstring.hpp>
|
||||
|
||||
namespace nall {
|
||||
template<> struct has_length<string> { enum { value = true }; };
|
||||
template<> struct has_size<lstring> { enum { value = true }; };
|
||||
|
@ -11,10 +11,25 @@
|
||||
#include <nall/vector.hpp>
|
||||
|
||||
namespace nall {
|
||||
class string;
|
||||
struct string;
|
||||
struct cstring;
|
||||
|
||||
class string {
|
||||
public:
|
||||
struct cstring {
|
||||
inline operator const char*() const;
|
||||
inline unsigned length() const;
|
||||
inline bool operator==(const char*) const;
|
||||
inline bool operator!=(const char*) const;
|
||||
inline optional<unsigned> position(const char *key) const;
|
||||
inline optional<unsigned> iposition(const char *key) const;
|
||||
inline cstring& operator=(const char *data);
|
||||
inline cstring(const char *data);
|
||||
inline cstring();
|
||||
|
||||
protected:
|
||||
const char *data;
|
||||
};
|
||||
|
||||
struct string {
|
||||
inline void reserve(unsigned);
|
||||
inline unsigned length() const;
|
||||
|
||||
@ -25,6 +40,11 @@ namespace nall {
|
||||
inline string& append(unsigned int value);
|
||||
inline string& append(double value);
|
||||
|
||||
inline char* begin() { return &data[0]; }
|
||||
inline char* end() { return &data[length()]; }
|
||||
inline const char* begin() const { return &data[0]; }
|
||||
inline const char* end() const { return &data[length()]; }
|
||||
|
||||
// <_______<
|
||||
template <typename T1, typename T2>
|
||||
inline string& append(const T1 &t1, const T2 &t2) { append(t1), append(t2); return *this; }
|
||||
@ -115,8 +135,7 @@ namespace nall {
|
||||
return t;
|
||||
}
|
||||
|
||||
class lstring : public linear_vector<string> {
|
||||
public:
|
||||
struct lstring : public linear_vector<string> {
|
||||
template<typename T> inline lstring& operator<<(const T& value);
|
||||
|
||||
inline optional<unsigned> find(const char*);
|
||||
@ -134,6 +153,9 @@ namespace nall {
|
||||
lstring(const string &, const string &, const string &, const string &, const string &, const string &, const string &);
|
||||
lstring(const string &, const string &, const string &, const string &, const string &, const string &, const string &, const string &);
|
||||
|
||||
inline bool operator==(const lstring&) const;
|
||||
inline bool operator!=(const lstring&) const;
|
||||
|
||||
lstring(const lstring & str);
|
||||
lstring(std::initializer_list<string>);
|
||||
};
|
||||
@ -168,6 +190,14 @@ namespace nall {
|
||||
inline unsigned strlcpy(char *dest, const char *src, unsigned length);
|
||||
inline unsigned strlcat(char *dest, const char *src, unsigned length);
|
||||
|
||||
//strpos.hpp
|
||||
inline optional<unsigned> strpos(const char *str, const char *key);
|
||||
inline optional<unsigned> istrpos(const char *str, const char *key);
|
||||
inline optional<unsigned> qstrpos(const char *str, const char *key);
|
||||
inline optional<unsigned> iqstrpos(const char *str, const char *key);
|
||||
template<bool Insensitive, bool Quoted> inline optional<unsigned> ustrpos(const char *str, const char *key);
|
||||
inline optional<unsigned> ustrpos(const char *str, const char *key) { return ustrpos<false, false>(str, key); }
|
||||
|
||||
//trim.hpp
|
||||
inline char* ltrim(char *str, const char *key = " ");
|
||||
inline char* rtrim(char *str, const char *key = " ");
|
||||
@ -181,7 +211,9 @@ namespace nall {
|
||||
inline unsigned strlcat(string &dest, const char *src, unsigned length);
|
||||
inline string substr(const char *src, unsigned start = 0, unsigned length = 0);
|
||||
inline string& strtr(string &dest, const char *before, const char *after);
|
||||
|
||||
template<bool Quoted, typename T> inline bool quoteskip(T *&p);
|
||||
template<bool Insensitive> inline bool chrequal(char x, char y);
|
||||
|
||||
inline string integer(intmax_t value);
|
||||
template<unsigned length> inline string linteger(intmax_t value);
|
||||
template<unsigned length> inline string rinteger(intmax_t value);
|
||||
|
153
nall/string/bml.hpp
Executable file
153
nall/string/bml.hpp
Executable file
@ -0,0 +1,153 @@
|
||||
#ifndef NALL_STRING_INTERNAL_HPP
|
||||
#define NALL_STRING_INTERNAL_HPP
|
||||
|
||||
//BML v1.0 parser
|
||||
//revision 0.05
|
||||
//
|
||||
|
||||
namespace nall {
|
||||
namespace BML {
|
||||
|
||||
inline static string indent(const char *s, unsigned depth) {
|
||||
array<char> output;
|
||||
do {
|
||||
for(unsigned n = 0; n < depth; n++) output.append('\t');
|
||||
do output.append(*s); while(*s && *s++ != '\n');
|
||||
} while(*s);
|
||||
return output.get();
|
||||
}
|
||||
|
||||
struct Node {
|
||||
cstring name;
|
||||
cstring value;
|
||||
|
||||
private:
|
||||
linear_vector<Node> children;
|
||||
|
||||
inline bool valid(char p) const { //A-Za-z0-9-.
|
||||
return p - 'A' < 26u | p - 'a' < 26u | p - '0' < 10u | p - '-' < 2u;
|
||||
}
|
||||
|
||||
inline unsigned parseDepth(char *&p) {
|
||||
while(*p == '\n' || *p == '#') {
|
||||
while(*p != '\n') *p++ = 0;
|
||||
*p++ = 0; //'\n'
|
||||
}
|
||||
unsigned depth = 0;
|
||||
while(p[depth] == '\t') depth++;
|
||||
return depth;
|
||||
}
|
||||
|
||||
inline void parseName(char *&p) {
|
||||
if(valid(*p) == false) throw "Missing node name";
|
||||
name = p;
|
||||
while(valid(*p)) p++;
|
||||
}
|
||||
|
||||
inline void parseValue(char *&p) {
|
||||
char terminal = *p == ':' ? '\n' : ' '; //':' or '='
|
||||
*p++ = 0;
|
||||
value = p;
|
||||
while(*p && *p != terminal && *p != '\n') p++;
|
||||
}
|
||||
|
||||
inline void parseBlock(char *&p, unsigned depth) {
|
||||
value = p;
|
||||
char *w = p;
|
||||
while(parseDepth(p) > depth) {
|
||||
p += depth + 1;
|
||||
while(*p && *p != '\n') *w++ = *p++;
|
||||
if(*p && *p != '\n') throw "Multi-line value missing line feed";
|
||||
*w++ = *p;
|
||||
}
|
||||
*(w - 1) = 0; //'\n'
|
||||
}
|
||||
|
||||
inline void parseLine(char *&p) {
|
||||
unsigned depth = parseDepth(p);
|
||||
while(*p == '\t') p++;
|
||||
|
||||
parseName(p);
|
||||
bool multiLine = *p == '~';
|
||||
if(multiLine) *p++ = 0;
|
||||
else if(*p == ':' || *p == '=') parseValue(p);
|
||||
if(*p && *p != ' ' && *p != '\n') throw "Invalid character encountered";
|
||||
|
||||
while(*p == ' ') {
|
||||
*p++ = 0;
|
||||
Node node;
|
||||
node.parseName(p);
|
||||
if(*p == ':' || *p == '=') node.parseValue(p);
|
||||
if(*p && *p != ' ' && *p != '\n') throw "Invalid character after node";
|
||||
if(*p == '\n') *p++ = 0;
|
||||
children.append(node);
|
||||
}
|
||||
|
||||
if(multiLine) return parseBlock(p, depth);
|
||||
|
||||
while(parseDepth(p) > depth) {
|
||||
Node node;
|
||||
node.parseLine(p);
|
||||
children.append(node);
|
||||
}
|
||||
}
|
||||
|
||||
inline void parse(char *&p) {
|
||||
while(*p) {
|
||||
Node node;
|
||||
node.parseLine(p);
|
||||
children.append(node);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
inline Node& operator[](const char *name) {
|
||||
foreach (node, children) {
|
||||
if(node.name == name) return node;
|
||||
}
|
||||
static Node node;
|
||||
node.name = 0;
|
||||
return node;
|
||||
}
|
||||
|
||||
inline bool exists() const { return name; }
|
||||
unsigned size() const { return children.size(); }
|
||||
Node* begin() { return children.begin(); }
|
||||
Node* end() { return children.end(); }
|
||||
const Node* begin() const { return children.begin(); }
|
||||
const Node* end() const { return children.end(); }
|
||||
inline Node() : name(""), value("") {}
|
||||
friend class Document;
|
||||
};
|
||||
|
||||
struct Document : Node {
|
||||
cstring error;
|
||||
|
||||
inline bool load(const char *document) {
|
||||
if(document == 0) return false;
|
||||
this->document = strdup(document);
|
||||
char *p = this->document;
|
||||
try {
|
||||
this->error = 0;
|
||||
parse(p);
|
||||
} catch(const char *error) {
|
||||
this->error = error;
|
||||
free(this->document);
|
||||
this->document = 0;
|
||||
children.reset();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline Document(const char *document = "") : document(0), error(0) { if(*document) load(document); }
|
||||
inline ~Document() { if(document) free(document); }
|
||||
|
||||
private:
|
||||
char *document;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
21
nall/string/cstring.hpp
Executable file
21
nall/string/cstring.hpp
Executable file
@ -0,0 +1,21 @@
|
||||
#ifdef NALL_STRING_INTERNAL_HPP
|
||||
|
||||
//const string:
|
||||
//bind a const char* pointer to an object that has various testing functionality;
|
||||
//yet lacks the memory allocation and modification functionality of the string class
|
||||
|
||||
namespace nall {
|
||||
|
||||
cstring::operator const char*() const { return data; }
|
||||
unsigned cstring::length() const { return strlen(data); }
|
||||
bool cstring::operator==(const char *s) const { return !strcmp(data, s); }
|
||||
bool cstring::operator!=(const char *s) const { return strcmp(data, s); }
|
||||
optional<unsigned> cstring::position (const char *key) const { return strpos(data, key); }
|
||||
optional<unsigned> cstring::iposition(const char *key) const { return istrpos(data, key); }
|
||||
cstring& cstring::operator=(const char *data) { this->data = data; return *this; }
|
||||
cstring::cstring(const char *data) : data(data) {}
|
||||
cstring::cstring() : data("") {}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -7,35 +7,28 @@
|
||||
|
||||
namespace nall {
|
||||
|
||||
inline optional<unsigned> strpos(const char *str, const char *key) {
|
||||
unsigned ssl = strlen(str), ksl = strlen(key);
|
||||
if(ksl > ssl) return optional<unsigned>(false, 0);
|
||||
template<bool Insensitive, bool Quoted>
|
||||
optional<unsigned> ustrpos(const char *str, const char *key) {
|
||||
const char *base = str;
|
||||
|
||||
for(unsigned i = 0; i <= ssl - ksl; i++) {
|
||||
if(!memcmp(str + i, key, ksl)) return optional<unsigned>(true, i);
|
||||
}
|
||||
|
||||
return optional<unsigned>(false, 0);
|
||||
}
|
||||
|
||||
inline optional<unsigned> qstrpos(const char *str, const char *key) {
|
||||
unsigned ssl = strlen(str), ksl = strlen(key);
|
||||
if(ksl > ssl) return optional<unsigned>(false, 0);
|
||||
|
||||
for(unsigned i = 0; i <= ssl - ksl;) {
|
||||
uint8_t x = str[i];
|
||||
if(x == '\"' || x == '\'') {
|
||||
uint8_t z = i++;
|
||||
while(str[i] != x && i < ssl) i++;
|
||||
if(i >= ssl) i = z;
|
||||
while(*str) {
|
||||
if(quoteskip<Quoted>(str)) continue;
|
||||
for(unsigned n = 0;; n++) {
|
||||
if(key[n] == 0) return optional<unsigned>(true, (unsigned)(str - base));
|
||||
if(str[n] == 0) return optional<unsigned>(false, 0);
|
||||
if(!chrequal<Insensitive>(str[n], key[n])) break;
|
||||
}
|
||||
if(!memcmp(str + i, key, ksl)) return optional<unsigned>(true, i);
|
||||
i++;
|
||||
str++;
|
||||
}
|
||||
|
||||
return optional<unsigned>(false, 0);
|
||||
}
|
||||
|
||||
optional<unsigned> strpos(const char *str, const char *key) { return ustrpos<false, false>(str, key); }
|
||||
optional<unsigned> istrpos(const char *str, const char *key) { return ustrpos<true, false>(str, key); }
|
||||
optional<unsigned> qstrpos(const char *str, const char *key) { return ustrpos<false, true>(str, key); }
|
||||
optional<unsigned> iqstrpos(const char *str, const char *key) { return ustrpos<true, true>(str, key); }
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -264,6 +264,24 @@ inline string sha256(const uint8_t *data, unsigned size) {
|
||||
return result;
|
||||
}
|
||||
|
||||
template<bool Insensitive>
|
||||
inline bool chrequal(char x, char y) {
|
||||
if(Insensitive) return chrlower(x) == chrlower(y);
|
||||
return x == y;
|
||||
}
|
||||
|
||||
template<bool Quoted, typename T>
|
||||
inline bool quoteskip(T *&p) {
|
||||
if(Quoted == false) return false;
|
||||
if(*p != '\'' && *p != '\"') return false;
|
||||
|
||||
while(*p == '\'' || *p == '\"') {
|
||||
char x = *p++;
|
||||
while(*p && *p++ != x);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -126,6 +126,12 @@ namespace nall {
|
||||
~linear_vector() {
|
||||
reset();
|
||||
}
|
||||
|
||||
//iteration
|
||||
T* begin() { return &pool[0]; }
|
||||
T* end() { return &pool[objectsize]; }
|
||||
const T* begin() const { return &pool[0]; }
|
||||
const T* end() const { return &pool[objectsize]; }
|
||||
};
|
||||
|
||||
//pointer_vector
|
||||
@ -240,6 +246,22 @@ namespace nall {
|
||||
~pointer_vector() {
|
||||
reset();
|
||||
}
|
||||
|
||||
//iteration
|
||||
struct iterator {
|
||||
bool operator!=(const iterator &source) const { return index != source.index; }
|
||||
T& operator*() { return vector.operator[](index); }
|
||||
iterator& operator++() { index++; return *this; }
|
||||
iterator(const pointer_vector &vector, unsigned index) : vector(vector), index(index) {}
|
||||
private:
|
||||
const pointer_vector &vector;
|
||||
unsigned index;
|
||||
};
|
||||
|
||||
iterator begin() { return iterator(*this, 0); }
|
||||
iterator end() { return iterator(*this, objectsize); }
|
||||
const iterator begin() const { return iterator(*this, 0); }
|
||||
const iterator end() const { return iterator(*this, objectsize); }
|
||||
};
|
||||
|
||||
template<typename T> struct has_size< linear_vector<T> > { enum { value = true }; };
|
||||
|
@ -1,5 +1,5 @@
|
||||
snes_objects := libco
|
||||
snes_objects += snes-system snes-controller
|
||||
snes_objects += snes-interface snes-system snes-controller
|
||||
snes_objects += snes-cartridge snes-cheat
|
||||
snes_objects += snes-memory snes-cpucore snes-smpcore
|
||||
snes_objects += snes-cpu snes-smp snes-dsp snes-ppu
|
||||
@ -34,6 +34,7 @@ obj/libsnes.o: $(snes)/libsnes/libsnes.cpp $(snes)/libsnes/*
|
||||
|
||||
obj/libco.o : libco/libco.c libco/*
|
||||
|
||||
obj/snes-interface.o : $(snes)/interface/interface.cpp $(call rwildcard,$(snes)/interface)
|
||||
obj/snes-system.o : $(snes)/system/system.cpp $(call rwildcard,$(snes)/system/) $(call rwildcard,$(snes)/video/) $(call rwildcard,$(snes)/audio/) $(call rwildcard,$(snes)/input/)
|
||||
obj/snes-controller.o: $(snes)/controller/controller.cpp $(call rwildcard,$(snes)/controller/)
|
||||
obj/snes-memory.o : $(snes)/memory/memory.cpp $(call rwildcard,$(snes)/memory/)
|
||||
|
@ -67,12 +67,14 @@ void CPU::enter() {
|
||||
|
||||
if(status.nmi_pending) {
|
||||
status.nmi_pending = false;
|
||||
op_irq(regs.e == false ? 0xffea : 0xfffa);
|
||||
regs.vector = (regs.e == false ? 0xffea : 0xfffa);
|
||||
op_irq();
|
||||
}
|
||||
|
||||
if(status.irq_pending) {
|
||||
status.irq_pending = false;
|
||||
op_irq(regs.e == false ? 0xffee : 0xfffe);
|
||||
regs.vector = (regs.e == false ? 0xffee : 0xfffe);
|
||||
op_irq();
|
||||
}
|
||||
|
||||
op_step();
|
||||
@ -83,21 +85,6 @@ alwaysinline void CPU::op_step() {
|
||||
(this->*opcode_table[op_readpc()])();
|
||||
}
|
||||
|
||||
void CPU::op_irq(uint16 vector) {
|
||||
op_read(regs.pc.d);
|
||||
op_io();
|
||||
if(!regs.e) op_writestack(regs.pc.b);
|
||||
op_writestack(regs.pc.h);
|
||||
op_writestack(regs.pc.l);
|
||||
op_writestack(regs.e ? (regs.p & ~0x10) : regs.p);
|
||||
rd.l = op_read(vector + 0);
|
||||
regs.pc.b = 0x00;
|
||||
regs.p.i = 1;
|
||||
regs.p.d = 0;
|
||||
rd.h = op_read(vector + 1);
|
||||
regs.pc.w = rd.w;
|
||||
}
|
||||
|
||||
static uint8 cpu_wram_reader(unsigned addr) {
|
||||
return cpu.wram[addr];
|
||||
}
|
||||
|
@ -35,7 +35,6 @@ private:
|
||||
//cpu
|
||||
static void Enter();
|
||||
debugvirtual void op_step();
|
||||
void op_irq(uint16 vector);
|
||||
|
||||
//timing
|
||||
struct QueueEvent {
|
||||
|
@ -134,9 +134,9 @@ void PPU::power() {
|
||||
ppu1_version = config.ppu1.version;
|
||||
ppu2_version = config.ppu2.version;
|
||||
|
||||
foreach(n, vram) n = 0x00;
|
||||
foreach(n, oam) n = 0x00;
|
||||
foreach(n, cgram) n = 0x00;
|
||||
for(auto &n : vram) n = 0x00;
|
||||
for(auto &n : oam) n = 0x00;
|
||||
for(auto &n : cgram) n = 0x00;
|
||||
flush_tiledata_cache();
|
||||
|
||||
region = (system.region.i == System::Region::NTSC ? 0 : 1); //0 = NTSC, 1 = PAL
|
||||
@ -351,7 +351,7 @@ void PPU::power() {
|
||||
void PPU::reset() {
|
||||
create(Enter, system.cpu_frequency);
|
||||
PPUcounter::reset();
|
||||
memset(surface, 0, 512 * 512 * sizeof(uint16));
|
||||
memset(surface, 0, 512 * 512 * sizeof(uint32));
|
||||
|
||||
frame();
|
||||
|
||||
@ -399,7 +399,7 @@ void PPU::set_frameskip(unsigned frameskip_) {
|
||||
}
|
||||
|
||||
PPU::PPU() {
|
||||
surface = new uint16[512 * 512];
|
||||
surface = new uint32[512 * 512];
|
||||
output = surface + 16 * 512;
|
||||
|
||||
alloc_tiledata_cache();
|
||||
@ -410,20 +410,6 @@ PPU::PPU() {
|
||||
}
|
||||
}
|
||||
|
||||
for(unsigned l = 0; l < 16; l++) {
|
||||
for(unsigned r = 0; r < 32; r++) {
|
||||
for(unsigned g = 0; g < 32; g++) {
|
||||
for(unsigned b = 0; b < 32; b++) {
|
||||
double luma = (double)l / 15.0;
|
||||
unsigned ar = static_cast<unsigned>(luma * r + 0.5);
|
||||
unsigned ag = static_cast<unsigned>(luma * g + 0.5);
|
||||
unsigned ab = static_cast<unsigned>(luma * b + 0.5);
|
||||
light_table[l][(r << 10) + (g << 5) + b] = (ab << 10) + (ag << 5) + ar;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
layer_enabled[BG1][0] = true;
|
||||
layer_enabled[BG1][1] = true;
|
||||
layer_enabled[BG2][0] = true;
|
||||
|
@ -12,8 +12,8 @@ public:
|
||||
#include "mmio/mmio.hpp"
|
||||
#include "render/render.hpp"
|
||||
|
||||
uint16 *surface;
|
||||
uint16 *output;
|
||||
uint32 *surface;
|
||||
uint32 *output;
|
||||
|
||||
uint8 ppu1_version;
|
||||
uint8 ppu2_version;
|
||||
@ -50,7 +50,6 @@ public:
|
||||
alwaysinline bool overscan() const { return display.overscan; }
|
||||
alwaysinline bool hires() const { return (regs.pseudo_hires || regs.bg_mode == 5 || regs.bg_mode == 6); }
|
||||
|
||||
uint16 light_table[16][32768];
|
||||
uint16 mosaic_table[16][4096];
|
||||
void render_line();
|
||||
|
||||
|
@ -85,13 +85,12 @@ inline uint16 PPU::get_pixel_swap(uint32 x) {
|
||||
}
|
||||
|
||||
inline void PPU::render_line_output() {
|
||||
uint16 *ptr = (uint16*)output + (line * 1024) + ((interlace() && field()) ? 512 : 0);
|
||||
uint16 *luma = light_table[regs.display_brightness];
|
||||
uint16 curr, prev;
|
||||
uint32 *ptr = (uint32*)output + (line * 1024) + ((interlace() && field()) ? 512 : 0);
|
||||
uint32 curr, prev;
|
||||
|
||||
if(!regs.pseudo_hires && regs.bg_mode != 5 && regs.bg_mode != 6) {
|
||||
for(unsigned x = 0; x < 256; x++) {
|
||||
curr = luma[get_pixel_normal(x)];
|
||||
curr = (regs.display_brightness << 15) | get_pixel_normal(x);
|
||||
*ptr++ = curr;
|
||||
}
|
||||
} else {
|
||||
@ -99,11 +98,11 @@ inline void PPU::render_line_output() {
|
||||
//blending is disabled below, as this should be done via video filtering
|
||||
//blending code is left for reference purposes
|
||||
|
||||
curr = luma[get_pixel_swap(x)];
|
||||
curr = (regs.display_brightness << 15) | get_pixel_swap(x);
|
||||
*ptr++ = curr; //(prev + curr - ((prev ^ curr) & 0x0421)) >> 1;
|
||||
//prev = curr;
|
||||
|
||||
curr = luma[get_pixel_normal(x)];
|
||||
curr = (regs.display_brightness << 15) | get_pixel_normal(x);
|
||||
*ptr++ = curr; //(prev + curr - ((prev ^ curr) & 0x0421)) >> 1;
|
||||
//prev = curr;
|
||||
}
|
||||
@ -111,9 +110,9 @@ inline void PPU::render_line_output() {
|
||||
}
|
||||
|
||||
inline void PPU::render_line_clear() {
|
||||
uint16 *ptr = (uint16*)output + (line * 1024) + ((interlace() && field()) ? 512 : 0);
|
||||
uint16 width = (!regs.pseudo_hires && regs.bg_mode != 5 && regs.bg_mode != 6) ? 256 : 512;
|
||||
memset(ptr, 0, width * 2 * sizeof(uint16));
|
||||
uint32 *ptr = (uint32*)output + (line * 1024) + ((interlace() && field()) ? 512 : 0);
|
||||
unsigned width = (!regs.pseudo_hires && regs.bg_mode != 5 && regs.bg_mode != 6) ? 256 : 512;
|
||||
memset(ptr, 0, width * 2 * sizeof(uint32));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -105,7 +105,7 @@ void PPU::power() {
|
||||
void PPU::reset() {
|
||||
create(Enter, system.cpu_frequency);
|
||||
PPUcounter::reset();
|
||||
memset(surface, 0, 512 * 512 * sizeof(uint16));
|
||||
memset(surface, 0, 512 * 512 * sizeof(uint32));
|
||||
mmio_reset();
|
||||
display.interlace = false;
|
||||
display.overscan = false;
|
||||
@ -141,7 +141,7 @@ bg3(*this, Background::ID::BG3),
|
||||
bg4(*this, Background::ID::BG4),
|
||||
sprite(*this),
|
||||
screen(*this) {
|
||||
surface = new uint16[512 * 512];
|
||||
surface = new uint32[512 * 512];
|
||||
output = surface + 16 * 512;
|
||||
display.width = 256;
|
||||
display.height = 224;
|
||||
|
@ -33,8 +33,8 @@ public:
|
||||
~PPU();
|
||||
|
||||
private:
|
||||
uint16 *surface;
|
||||
uint16 *output;
|
||||
uint32 *surface;
|
||||
uint32 *output;
|
||||
|
||||
#include "mmio/mmio.hpp"
|
||||
#include "window/window.hpp"
|
||||
|
@ -55,9 +55,9 @@ void PPU::Screen::scanline() {
|
||||
}
|
||||
|
||||
void PPU::Screen::render_black() {
|
||||
uint16 *data = self.output + self.vcounter() * 1024;
|
||||
uint32 *data = self.output + self.vcounter() * 1024;
|
||||
if(self.interlace() && self.field()) data += 512;
|
||||
memset(data, 0, self.display.width << 1);
|
||||
memset(data, 0, self.display.width << 2);
|
||||
}
|
||||
|
||||
uint16 PPU::Screen::get_pixel_main(unsigned x) {
|
||||
@ -117,41 +117,23 @@ uint16 PPU::Screen::get_pixel_sub(unsigned x) {
|
||||
void PPU::Screen::render() {
|
||||
uint16 *data = self.output + self.vcounter() * 1024;
|
||||
if(self.interlace() && self.field()) data += 512;
|
||||
uint16 *light = light_table[self.regs.display_brightness];
|
||||
|
||||
if(!self.regs.pseudo_hires && self.regs.bgmode != 5 && self.regs.bgmode != 6) {
|
||||
for(unsigned i = 0; i < 256; i++) {
|
||||
data[i] = light[get_pixel_main(i)];
|
||||
data[i] = (self.regs.display_brightness << 15) | get_pixel_main(i);
|
||||
}
|
||||
} else {
|
||||
for(unsigned i = 0; i < 256; i++) {
|
||||
*data++ = light[get_pixel_sub(i)];
|
||||
*data++ = light[get_pixel_main(i)];
|
||||
*data++ = (self.regs.display_brightness << 15) | get_pixel_sub(i);
|
||||
*data++ = (self.regs.display_brightness << 15) | get_pixel_main(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PPU::Screen::Screen(PPU &self) : self(self) {
|
||||
light_table = new uint16*[16];
|
||||
for(unsigned l = 0; l < 16; l++) {
|
||||
light_table[l] = new uint16[32768];
|
||||
for(unsigned r = 0; r < 32; r++) {
|
||||
for(unsigned g = 0; g < 32; g++) {
|
||||
for(unsigned b = 0; b < 32; b++) {
|
||||
double luma = (double)l / 15.0;
|
||||
unsigned ar = static_cast<unsigned>(luma * r + 0.5);
|
||||
unsigned ag = static_cast<unsigned>(luma * g + 0.5);
|
||||
unsigned ab = static_cast<unsigned>(luma * b + 0.5);
|
||||
light_table[l][(r << 10) + (g << 5) + (b << 0)] = (ab << 10) + (ag << 5) + (ar << 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PPU::Screen::~Screen() {
|
||||
for(unsigned l = 0; l < 16; l++) delete[] light_table[l];
|
||||
delete[] light_table;
|
||||
}
|
||||
|
||||
void PPU::Screen::Output::plot_main(unsigned x, unsigned color, unsigned priority, unsigned source) {
|
||||
|
@ -25,7 +25,6 @@ struct Screen {
|
||||
} output;
|
||||
|
||||
ColorWindow window;
|
||||
uint16 **light_table;
|
||||
|
||||
alwaysinline unsigned get_palette(unsigned color);
|
||||
unsigned get_direct_color(unsigned palette, unsigned tile);
|
||||
|
@ -110,6 +110,13 @@ void SMP::serialize(serializer &s) {
|
||||
s.integer(regs.p.z);
|
||||
s.integer(regs.p.c);
|
||||
|
||||
s.integer(rd);
|
||||
s.integer(wr);
|
||||
s.integer(dp);
|
||||
s.integer(sp);
|
||||
s.integer(ya);
|
||||
s.integer(bit);
|
||||
|
||||
s.integer(status.iplrom_enable);
|
||||
|
||||
s.integer(status.dsp_addr);
|
||||
@ -135,13 +142,6 @@ void SMP::serialize(serializer &s) {
|
||||
s.integer(timer2.stage1_ticks);
|
||||
s.integer(timer2.stage2_ticks);
|
||||
s.integer(timer2.stage3_ticks);
|
||||
|
||||
s.integer(rd);
|
||||
s.integer(wr);
|
||||
s.integer(dp);
|
||||
s.integer(sp);
|
||||
s.integer(ya);
|
||||
s.integer(bit);
|
||||
}
|
||||
|
||||
SMP::SMP() {
|
||||
|
@ -44,8 +44,6 @@ public:
|
||||
unsigned opcode_number;
|
||||
unsigned opcode_cycle;
|
||||
|
||||
unsigned rd, wr, dp, sp, ya, bit;
|
||||
|
||||
struct Regs {
|
||||
uint16 pc;
|
||||
uint8 sp;
|
||||
@ -57,6 +55,8 @@ public:
|
||||
Flags p;
|
||||
} regs;
|
||||
|
||||
unsigned rd, wr, dp, sp, ya, bit;
|
||||
|
||||
struct Status {
|
||||
//$00f1
|
||||
bool iplrom_enable;
|
||||
|
@ -19,15 +19,13 @@ void Audio::coprocessor_frequency(double input_frequency) {
|
||||
r_frac = 0;
|
||||
}
|
||||
|
||||
void Audio::sample(int16 left, int16 right) {
|
||||
if(coprocessor == false) {
|
||||
system.interface->audio_sample(left, right);
|
||||
} else {
|
||||
dsp_buffer[dsp_wroffset] = ((uint16)left << 0) + ((uint16)right << 16);
|
||||
dsp_wroffset = (dsp_wroffset + 1) & buffer_mask;
|
||||
dsp_length = (dsp_length + 1) & buffer_mask;
|
||||
flush();
|
||||
}
|
||||
void Audio::sample(int16 lsample, int16 rsample) {
|
||||
if(coprocessor == false) return interface->audioSample(lsample, rsample);
|
||||
|
||||
dsp_buffer[dsp_wroffset] = ((uint16)lsample << 0) + ((uint16)rsample << 16);
|
||||
dsp_wroffset = (dsp_wroffset + 1) & buffer_mask;
|
||||
dsp_length = (dsp_length + 1) & buffer_mask;
|
||||
flush();
|
||||
}
|
||||
|
||||
void Audio::coprocessor_sample(int16 left, int16 right) {
|
||||
@ -69,13 +67,13 @@ void Audio::flush() {
|
||||
dsp_length--;
|
||||
cop_length--;
|
||||
|
||||
int dsp_left = (int16)(dsp_sample >> 0);
|
||||
int dsp_right = (int16)(dsp_sample >> 16);
|
||||
signed dsp_left = (int16)(dsp_sample >> 0);
|
||||
signed dsp_right = (int16)(dsp_sample >> 16);
|
||||
|
||||
int cop_left = (int16)(cop_sample >> 0);
|
||||
int cop_right = (int16)(cop_sample >> 16);
|
||||
signed cop_left = (int16)(cop_sample >> 0);
|
||||
signed cop_right = (int16)(cop_sample >> 16);
|
||||
|
||||
system.interface->audio_sample(
|
||||
interface->audioSample(
|
||||
sclamp<16>((dsp_left + cop_left ) / 2),
|
||||
sclamp<16>((dsp_right + cop_right) / 2)
|
||||
);
|
||||
|
@ -1,9 +1,8 @@
|
||||
class Audio {
|
||||
public:
|
||||
struct Audio {
|
||||
void coprocessor_enable(bool state);
|
||||
void coprocessor_frequency(double frequency);
|
||||
void sample(int16 left, int16 right);
|
||||
void coprocessor_sample(int16 left, int16 right);
|
||||
void sample(int16 lsample, int16 rsample);
|
||||
void coprocessor_sample(int16 lsample, int16 rsample);
|
||||
void init();
|
||||
|
||||
private:
|
||||
|
@ -6,12 +6,12 @@
|
||||
#define CARTRIDGE_CPP
|
||||
namespace SNES {
|
||||
|
||||
#include "xml.cpp"
|
||||
#include "markup.cpp"
|
||||
#include "serialization.cpp"
|
||||
|
||||
Cartridge cartridge;
|
||||
|
||||
void Cartridge::load(Mode::e cartridge_mode, const lstring &xml_list) {
|
||||
void Cartridge::load(Mode::e cartridge_mode, const char *markup) {
|
||||
mode.i = cartridge_mode;
|
||||
region.i = Region::NTSC;
|
||||
ram_size = 0;
|
||||
@ -33,8 +33,8 @@ void Cartridge::load(Mode::e cartridge_mode, const lstring &xml_list) {
|
||||
|
||||
nvram.reset();
|
||||
|
||||
parse_xml(xml_list);
|
||||
//print(xml_list[0], "\n\n");
|
||||
parse_markup(markup);
|
||||
//print(markup, "\n\n");
|
||||
|
||||
if(ram_size > 0) {
|
||||
ram.map(allocate<uint8>(ram_size, 0xff), ram_size);
|
||||
@ -46,16 +46,21 @@ void Cartridge::load(Mode::e cartridge_mode, const lstring &xml_list) {
|
||||
|
||||
crc32 = crc32_calculate(rom.data(), rom.size());
|
||||
|
||||
sha256_ctx sha;
|
||||
uint8_t shahash[32];
|
||||
sha256_init(&sha);
|
||||
sha256_chunk(&sha, rom.data(), rom.size());
|
||||
sha256_final(&sha);
|
||||
sha256_hash(&sha, shahash);
|
||||
|
||||
string hash;
|
||||
foreach(n, shahash) hash.append(hex<2>(n));
|
||||
sha256 = hash;
|
||||
switch(mode.i) {
|
||||
case Mode::Normal:
|
||||
case Mode::BsxSlotted:
|
||||
sha256 = nall::sha256(rom.data(), rom.size());
|
||||
break;
|
||||
case Mode::Bsx:
|
||||
sha256 = nall::sha256(bsxflash.memory.data(), bsxflash.memory.size());
|
||||
break;
|
||||
case Mode::SufamiTurbo:
|
||||
sha256 = nall::sha256(sufamiturbo.slotA.rom.data(), sufamiturbo.slotA.rom.size());
|
||||
break;
|
||||
case Mode::SuperGameBoy:
|
||||
sha256 = GameBoy::cartridge.sha256();
|
||||
break;
|
||||
}
|
||||
|
||||
system.load();
|
||||
loaded = true;
|
||||
|
@ -1,5 +1,4 @@
|
||||
class Cartridge : property<Cartridge> {
|
||||
public:
|
||||
struct Cartridge : property<Cartridge> {
|
||||
struct Mode {
|
||||
enum e {
|
||||
Normal,
|
||||
@ -86,7 +85,7 @@ public:
|
||||
} nss;
|
||||
} information;
|
||||
|
||||
void load(Mode::e, const lstring&);
|
||||
void load(Mode::e, const char*);
|
||||
void unload();
|
||||
|
||||
void serialize(serializer&);
|
||||
@ -94,35 +93,27 @@ public:
|
||||
~Cartridge();
|
||||
|
||||
private:
|
||||
void parse_xml(const lstring&);
|
||||
void parse_xml_cartridge(const char*);
|
||||
void parse_xml_bsx(const char*);
|
||||
void parse_xml_sufami_turbo(const char*, bool);
|
||||
void parse_xml_gameboy(const char*);
|
||||
void parse_markup(const char*);
|
||||
unsigned parse_markup_integer(cstring&);
|
||||
void parse_markup_map(Mapping&, BML::Node&);
|
||||
|
||||
void xml_parse_rom(xml_element&);
|
||||
void xml_parse_ram(xml_element&);
|
||||
void xml_parse_nss(xml_element&);
|
||||
void xml_parse_icd2(xml_element&);
|
||||
void xml_parse_superfx(xml_element&);
|
||||
void xml_parse_sa1(xml_element&);
|
||||
void xml_parse_necdsp(xml_element&);
|
||||
void xml_parse_hitachidsp(xml_element&);
|
||||
void xml_parse_bsx(xml_element&);
|
||||
void xml_parse_sufamiturbo(xml_element&);
|
||||
void xml_parse_supergameboy(xml_element&);
|
||||
void xml_parse_srtc(xml_element&);
|
||||
void xml_parse_sdd1(xml_element&);
|
||||
void xml_parse_spc7110(xml_element&);
|
||||
void xml_parse_obc1(xml_element&);
|
||||
void xml_parse_setarisc(xml_element&);
|
||||
void xml_parse_msu1(xml_element&);
|
||||
void xml_parse_link(xml_element&);
|
||||
|
||||
unsigned xml_parse_hex(const string&);
|
||||
unsigned xml_parse_unsigned(const string&);
|
||||
void xml_parse_address(Mapping&, const string&);
|
||||
void xml_parse_mode(Mapping&, const string&);
|
||||
void parse_markup_rom(BML::Node&);
|
||||
void parse_markup_ram(BML::Node&);
|
||||
void parse_markup_nss(BML::Node&);
|
||||
void parse_markup_icd2(BML::Node&);
|
||||
void parse_markup_superfx(BML::Node&);
|
||||
void parse_markup_sa1(BML::Node&);
|
||||
void parse_markup_necdsp(BML::Node&);
|
||||
void parse_markup_hitachidsp(BML::Node&);
|
||||
void parse_markup_bsx(BML::Node&);
|
||||
void parse_markup_sufamiturbo(BML::Node&);
|
||||
void parse_markup_srtc(BML::Node&);
|
||||
void parse_markup_sdd1(BML::Node&);
|
||||
void parse_markup_spc7110(BML::Node&);
|
||||
void parse_markup_obc1(BML::Node&);
|
||||
void parse_markup_setarisc(BML::Node&);
|
||||
void parse_markup_msu1(BML::Node&);
|
||||
void parse_markup_link(BML::Node&);
|
||||
};
|
||||
|
||||
extern Cartridge cartridge;
|
||||
|
557
snes/cartridge/markup.cpp
Normal file
557
snes/cartridge/markup.cpp
Normal file
@ -0,0 +1,557 @@
|
||||
#ifdef CARTRIDGE_CPP
|
||||
|
||||
void Cartridge::parse_markup(const char *markup) {
|
||||
mapping.reset();
|
||||
information.nss.setting.reset();
|
||||
|
||||
BML::Document document(markup);
|
||||
auto &cartridge = document["cartridge"];
|
||||
region = cartridge["region"].value != "PAL" ? Region::NTSC : Region::PAL;
|
||||
|
||||
parse_markup_rom(cartridge["rom"]);
|
||||
parse_markup_ram(cartridge["ram"]);
|
||||
parse_markup_nss(cartridge["nss"]);
|
||||
parse_markup_icd2(cartridge["icd2"]);
|
||||
parse_markup_sa1(cartridge["sa1"]);
|
||||
parse_markup_superfx(cartridge["superfx"]);
|
||||
parse_markup_necdsp(cartridge["necdsp"]);
|
||||
parse_markup_hitachidsp(cartridge["hitachidsp"]);
|
||||
parse_markup_bsx(cartridge["bsx"]);
|
||||
parse_markup_sufamiturbo(cartridge["sufamiturbo"]);
|
||||
parse_markup_srtc(cartridge["srtc"]);
|
||||
parse_markup_sdd1(cartridge["sdd1"]);
|
||||
parse_markup_spc7110(cartridge["spc7110"]);
|
||||
parse_markup_obc1(cartridge["obc1"]);
|
||||
parse_markup_setarisc(cartridge["setarisc"]);
|
||||
parse_markup_msu1(cartridge["msu1"]);
|
||||
parse_markup_link(cartridge["link"]);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
unsigned Cartridge::parse_markup_integer(cstring &data) {
|
||||
if(strbegin(data, "0x")) return hex(data);
|
||||
return decimal(data);
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_map(Mapping &m, BML::Node &map) {
|
||||
m.offset = parse_markup_integer(map["offset"].value);
|
||||
m.size = parse_markup_integer(map["size"].value);
|
||||
|
||||
string data = map["mode"].value;
|
||||
if(data == "direct") m.mode = Bus::MapMode::Direct;
|
||||
if(data == "linear") m.mode = Bus::MapMode::Linear;
|
||||
if(data == "shadow") m.mode = Bus::MapMode::Shadow;
|
||||
|
||||
lstring part;
|
||||
part.split(":", map["address"].value);
|
||||
if(part.size() != 2) return;
|
||||
|
||||
lstring subpart;
|
||||
subpart.split("-", part[0]);
|
||||
if(subpart.size() == 1) {
|
||||
m.banklo = hex(subpart[0]);
|
||||
m.bankhi = m.banklo;
|
||||
} else if(subpart.size() == 2) {
|
||||
m.banklo = hex(subpart[0]);
|
||||
m.bankhi = hex(subpart[1]);
|
||||
}
|
||||
|
||||
subpart.split("-", part[1]);
|
||||
if(subpart.size() == 1) {
|
||||
m.addrlo = hex(subpart[0]);
|
||||
m.addrhi = m.addrlo;
|
||||
} else if(subpart.size() == 2) {
|
||||
m.addrlo = hex(subpart[0]);
|
||||
m.addrhi = hex(subpart[1]);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
void Cartridge::parse_markup_rom(BML::Node &root) {
|
||||
if(root.exists() == false) return;
|
||||
foreach(node, root) {
|
||||
if(node.name != "map") continue;
|
||||
Mapping m(rom);
|
||||
parse_markup_map(m, node);
|
||||
if(m.size == 0) m.size = rom.size();
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_ram(BML::Node &root) {
|
||||
if(root.exists() == false) return;
|
||||
ram_size = parse_markup_integer(root["size"].value);
|
||||
foreach(node, root) {
|
||||
Mapping m(ram);
|
||||
parse_markup_map(m, node);
|
||||
if(m.size == 0) m.size = ram_size;
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_nss(BML::Node &root) {
|
||||
if(root.exists() == false) return;
|
||||
has_nss_dip = true;
|
||||
foreach(node, root) {
|
||||
if(node.name != "setting") continue;
|
||||
unsigned number = information.nss.setting.size();
|
||||
if(number >= 16) break; //more than 16 DIP switches is not physically possible
|
||||
|
||||
information.nss.option[number].reset();
|
||||
information.nss.setting[number] = node["name"].value;
|
||||
foreach(leaf, node) {
|
||||
if(leaf.name != "option") continue;
|
||||
string name = leaf["name"].value;
|
||||
unsigned value = parse_markup_integer(leaf["value"].value);
|
||||
information.nss.option[number].append({ hex<4>(value), ":", name });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_icd2(BML::Node &root) {
|
||||
if(root.exists() == false) return;
|
||||
if(mode != Mode::SuperGameBoy) return;
|
||||
|
||||
icd2.revision = max(1, parse_markup_integer(root["revision"].value));
|
||||
|
||||
foreach(node, root) {
|
||||
if(node.name != "map") continue;
|
||||
Mapping m({ &ICD2::read, &icd2 }, { &ICD2::write, &icd2 });
|
||||
parse_markup_map(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_superfx(BML::Node &root) {
|
||||
if(root.exists() == false) return;
|
||||
has_superfx = true;
|
||||
|
||||
foreach(node, root) {
|
||||
if(node.name == "rom") {
|
||||
foreach(leaf, node) {
|
||||
if(leaf.name != "map") continue;
|
||||
Mapping m(superfx.rom);
|
||||
parse_markup_map(m, leaf);
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
if(node.name == "ram") {
|
||||
foreach(leaf, node) {
|
||||
if(leaf.name == "size") {
|
||||
ram_size = parse_markup_integer(leaf.value);
|
||||
continue;
|
||||
}
|
||||
if(leaf.name != "map") continue;
|
||||
Mapping m(superfx.ram);
|
||||
parse_markup_map(m, leaf);
|
||||
if(m.size == 0) m.size = ram_size;
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
if(node.name == "mmio") {
|
||||
foreach(leaf, node) {
|
||||
if(leaf.name != "map") continue;
|
||||
Mapping m({ &SuperFX::mmio_read, &superfx }, { &SuperFX::mmio_write, &superfx });
|
||||
parse_markup_map(m, leaf);
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_sa1(BML::Node &root) {
|
||||
if(root.exists() == false) return;
|
||||
has_sa1 = true;
|
||||
|
||||
auto &mcurom = root["mcu"]["rom"];
|
||||
auto &mcuram = root["mcu"]["ram"];
|
||||
auto &iram = root["iram"];
|
||||
auto &bwram = root["bwram"];
|
||||
auto &mmio = root["mmio"];
|
||||
|
||||
foreach(node, mcurom) {
|
||||
if(node.name != "map") continue;
|
||||
Mapping m({ &SA1::mmc_read, &sa1 }, { &SA1::mmc_write, &sa1 });
|
||||
parse_markup_map(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
|
||||
foreach(node, mcuram) {
|
||||
if(node.name != "map") continue;
|
||||
Mapping m({ &SA1::mmc_cpu_read, &sa1 }, { &SA1::mmc_cpu_write, &sa1 });
|
||||
parse_markup_map(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
|
||||
foreach(node, iram) {
|
||||
if(node.name != "map") continue;
|
||||
Mapping m(sa1.cpuiram);
|
||||
parse_markup_map(m, node);
|
||||
if(m.size == 0) m.size = 2048;
|
||||
mapping.append(m);
|
||||
}
|
||||
|
||||
ram_size = parse_markup_integer(bwram["size"].value);
|
||||
foreach(node, bwram) {
|
||||
if(node.name != "map") continue;
|
||||
Mapping m(sa1.cpubwram);
|
||||
parse_markup_map(m, node);
|
||||
if(m.size == 0) m.size = ram_size;
|
||||
mapping.append(m);
|
||||
}
|
||||
|
||||
foreach(node, mmio) {
|
||||
if(node.name != "map") continue;
|
||||
Mapping m({ &SA1::mmio_read, &sa1 }, { &SA1::mmio_write, &sa1 });
|
||||
parse_markup_map(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_necdsp(BML::Node &root) {
|
||||
if(root.exists() == false) return;
|
||||
has_necdsp = true;
|
||||
|
||||
for(unsigned n = 0; n < 16384; n++) necdsp.programROM[n] = 0x000000;
|
||||
for(unsigned n = 0; n < 2048; n++) necdsp.dataROM[n] = 0x0000;
|
||||
|
||||
necdsp.frequency = parse_markup_integer(root["frequency"].value);
|
||||
if(necdsp.frequency == 0) necdsp.frequency = 8000000;
|
||||
necdsp.revision
|
||||
= root["model"].value == "uPD7725" ? NECDSP::Revision::uPD7725
|
||||
: root["model"].value == "uPD96050" ? NECDSP::Revision::uPD96050
|
||||
: NECDSP::Revision::uPD7725;
|
||||
string firmware = root["firmware"].value;
|
||||
string sha256 = root["sha256"].value;
|
||||
|
||||
string path = { dir(interface->path(Slot::Base, ".dsp")), firmware };
|
||||
unsigned promsize = (necdsp.revision == NECDSP::Revision::uPD7725 ? 2048 : 16384);
|
||||
unsigned dromsize = (necdsp.revision == NECDSP::Revision::uPD7725 ? 1024 : 2048);
|
||||
unsigned filesize = promsize * 3 + dromsize * 2;
|
||||
|
||||
file fp;
|
||||
if(fp.open(path, file::mode::read) == false) {
|
||||
interface->message({ "Warning: NEC DSP firmware ", firmware, " is missing." });
|
||||
} else if(fp.size() != filesize) {
|
||||
interface->message({ "Warning: NEC DSP firmware ", firmware, " is of the wrong file size." });
|
||||
fp.close();
|
||||
} else {
|
||||
for(unsigned n = 0; n < promsize; n++) necdsp.programROM[n] = fp.readm(3);
|
||||
for(unsigned n = 0; n < dromsize; n++) necdsp.dataROM[n] = fp.readm(2);
|
||||
|
||||
if(sha256 != "") {
|
||||
//XML file specified SHA256 sum for program. Verify file matches the hash.
|
||||
fp.seek(0);
|
||||
uint8_t data[filesize];
|
||||
fp.read(data, filesize);
|
||||
|
||||
if(sha256 != nall::sha256(data, filesize)) {
|
||||
interface->message({ "Warning: NEC DSP firmware ", firmware, " SHA256 sum is incorrect." });
|
||||
}
|
||||
}
|
||||
|
||||
fp.close();
|
||||
}
|
||||
|
||||
foreach(node, root) {
|
||||
if(node.name == "dr") {
|
||||
foreach(leaf, node) {
|
||||
Mapping m({ &NECDSP::dr_read, &necdsp }, { &NECDSP::dr_write, &necdsp });
|
||||
parse_markup_map(m, leaf);
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
if(node.name == "sr") {
|
||||
foreach(leaf, node) {
|
||||
Mapping m({ &NECDSP::sr_read, &necdsp }, { &NECDSP::sr_write, &necdsp });
|
||||
parse_markup_map(m, leaf);
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
if(node.name == "dp") {
|
||||
foreach(leaf, node) {
|
||||
Mapping m({ &NECDSP::dp_read, &necdsp }, { &NECDSP::dp_write, &necdsp });
|
||||
parse_markup_map(m, leaf);
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_hitachidsp(BML::Node &root) {
|
||||
if(root.exists() == false) return;
|
||||
has_hitachidsp = true;
|
||||
|
||||
for(unsigned n = 0; n < 1024; n++) hitachidsp.dataROM[n] = 0x000000;
|
||||
|
||||
hitachidsp.frequency = parse_markup_integer(root["frequency"].value);
|
||||
if(hitachidsp.frequency == 0) hitachidsp.frequency = 20000000;
|
||||
string firmware = root["firmware"].value;
|
||||
string sha256 = root["sha256"].value;
|
||||
|
||||
string path = { dir(interface->path(Slot::Base, ".dsp")), firmware };
|
||||
file fp;
|
||||
if(fp.open(path, file::mode::read) == false) {
|
||||
interface->message({ "Warning: Hitachi DSP firmware ", firmware, " is missing." });
|
||||
} else if(fp.size() != 1024 * 3) {
|
||||
interface->message({ "Warning: Hitachi DSP firmware ", firmware, " is of the wrong file size." });
|
||||
fp.close();
|
||||
} else {
|
||||
for(unsigned n = 0; n < 1024; n++) hitachidsp.dataROM[n] = fp.readl(3);
|
||||
|
||||
if(sha256 != "") {
|
||||
//XML file specified SHA256 sum for program. Verify file matches the hash.
|
||||
fp.seek(0);
|
||||
uint8 data[3072];
|
||||
fp.read(data, 3072);
|
||||
|
||||
if(sha256 != nall::sha256(data, 3072)) {
|
||||
interface->message({ "Warning: Hitachi DSP firmware ", firmware, " SHA256 sum is incorrect." });
|
||||
}
|
||||
}
|
||||
|
||||
fp.close();
|
||||
}
|
||||
|
||||
foreach(node, root) {
|
||||
if(node.name == "rom") {
|
||||
foreach(leaf, node) {
|
||||
if(leaf.name != "map") continue;
|
||||
Mapping m({ &HitachiDSP::rom_read, &hitachidsp }, { &HitachiDSP::rom_write, &hitachidsp });
|
||||
parse_markup_map(m, leaf);
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
if(node.name == "mmio") {
|
||||
foreach(leaf, node) {
|
||||
Mapping m({ &HitachiDSP::dsp_read, &hitachidsp }, { &HitachiDSP::dsp_write, &hitachidsp });
|
||||
parse_markup_map(m, leaf);
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_bsx(BML::Node &root) {
|
||||
if(root.exists() == false) return;
|
||||
if(mode != Mode::BsxSlotted && mode != Mode::Bsx) return;
|
||||
|
||||
foreach(node, root["slot"]) {
|
||||
if(node.name != "map") continue;
|
||||
Mapping m(bsxflash.memory);
|
||||
parse_markup_map(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
|
||||
foreach(node, root["mmio"]) {
|
||||
if(node.name != "map") continue;
|
||||
Mapping m({ &BSXCartridge::mmio_read, &bsxcartridge }, { &BSXCartridge::mmio_write, &bsxcartridge });
|
||||
parse_markup_map(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
|
||||
foreach(node, root["mcu"]) {
|
||||
if(node.name != "map") continue;
|
||||
Mapping m({ &BSXCartridge::mcu_read, &bsxcartridge }, { &BSXCartridge::mcu_write, &bsxcartridge });
|
||||
parse_markup_map(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_sufamiturbo(BML::Node &root) {
|
||||
if(root.exists() == false) return;
|
||||
if(mode != Mode::SufamiTurbo) return;
|
||||
|
||||
foreach(slot, root) {
|
||||
if(slot.name != "slot") continue;
|
||||
bool slotid = slot["id"].value == "A" ? 0 : slot["id"].value == "B" ? 1 : 0;
|
||||
foreach(node, slot) {
|
||||
if(node.name == "rom") {
|
||||
foreach(leaf, node) {
|
||||
if(leaf.name != "map") continue;
|
||||
Memory &memory = slotid == 0 ? sufamiturbo.slotA.rom : sufamiturbo.slotB.rom;
|
||||
Mapping m(memory);
|
||||
parse_markup_map(m, leaf);
|
||||
if(m.size == 0) m.size = memory.size();
|
||||
if(m.size) mapping.append(m);
|
||||
}
|
||||
}
|
||||
if(node.name == "ram") {
|
||||
unsigned ram_size = parse_markup_integer(node["size"].value);
|
||||
foreach(leaf, node) {
|
||||
if(leaf.name != "map") continue;
|
||||
Memory &memory = slotid == 0 ? sufamiturbo.slotA.ram : sufamiturbo.slotB.ram;
|
||||
Mapping m(memory);
|
||||
parse_markup_map(m, leaf);
|
||||
if(m.size == 0) m.size = ram_size;
|
||||
if(m.size) mapping.append(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_srtc(BML::Node &root) {
|
||||
if(root.exists() == false) return;
|
||||
has_srtc = true;
|
||||
|
||||
foreach(node, root) {
|
||||
if(node.name != "map") continue;
|
||||
Mapping m({ &SRTC::read, &srtc }, { &SRTC::write, &srtc });
|
||||
parse_markup_map(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_sdd1(BML::Node &root) {
|
||||
if(root.exists() == false) return;
|
||||
has_sdd1 = true;
|
||||
|
||||
foreach(node, root["mmio"]) {
|
||||
if(node.name != "map") continue;
|
||||
Mapping m({ &SDD1::mmio_read, &sdd1 }, { &SDD1::mmio_write, &sdd1 });
|
||||
parse_markup_map(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
|
||||
foreach(node, root["mcu"]) {
|
||||
if(node.name != "map") continue;
|
||||
Mapping m({ &SDD1::mcu_read, &sdd1 }, { &SDD1::mcu_write, &sdd1 });
|
||||
parse_markup_map(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_spc7110(BML::Node &root) {
|
||||
if(root.exists() == false) return;
|
||||
has_spc7110 = true;
|
||||
|
||||
auto &ram = root["ram"];
|
||||
auto &mmio = root["mmio"];
|
||||
auto &mcu = root["mcu"];
|
||||
auto &dcu = root["dcu"];
|
||||
auto &rtc = root["rtc"];
|
||||
|
||||
ram_size = parse_markup_integer(ram["size"].value);
|
||||
foreach(node, ram) {
|
||||
if(node.name != "map") continue;
|
||||
Mapping m({ &SPC7110::ram_read, &spc7110 }, { &SPC7110::ram_write, &spc7110 });
|
||||
parse_markup_map(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
|
||||
foreach(node, mmio) {
|
||||
if(node.name != "map") continue;
|
||||
Mapping m({ &SPC7110::mmio_read, &spc7110 }, { &SPC7110::mmio_write, &spc7110 });
|
||||
parse_markup_map(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
|
||||
spc7110.data_rom_offset = parse_markup_integer(mcu["offset"].value);
|
||||
if(spc7110.data_rom_offset == 0) spc7110.data_rom_offset = 0x100000;
|
||||
foreach(node, mcu) {
|
||||
if(node.name != "map") continue;
|
||||
Mapping m({ &SPC7110::mcu_read, &spc7110 }, { &SPC7110::mcu_write, &spc7110 });
|
||||
parse_markup_map(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
|
||||
foreach(node, dcu) {
|
||||
if(node.name != "map") continue;
|
||||
Mapping m({ &SPC7110::dcu_read, &spc7110 }, { &SPC7110::dcu_write, &spc7110 });
|
||||
parse_markup_map(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
|
||||
foreach(node, rtc) {
|
||||
if(node.name != "map") continue;
|
||||
Mapping m({ &SPC7110::mmio_read, &spc7110 }, { &SPC7110::mmio_write, &spc7110 });
|
||||
parse_markup_map(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_obc1(BML::Node &root) {
|
||||
if(root.exists() == false) return;
|
||||
has_obc1 = true;
|
||||
|
||||
foreach(node, root) {
|
||||
if(node.name != "map") continue;
|
||||
Mapping m({ &OBC1::read, &obc1 }, { &OBC1::write, &obc1 });
|
||||
parse_markup_map(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_setarisc(BML::Node &root) {
|
||||
if(root.exists() == false) return;
|
||||
has_st0018 = true;
|
||||
|
||||
foreach(node, root) {
|
||||
if(node.name != "map") continue;
|
||||
Mapping m({ &ST0018::mmio_read, &st0018 }, { &ST0018::mmio_write, &st0018 });
|
||||
parse_markup_map(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_msu1(BML::Node &root) {
|
||||
if(root.exists() == false) {
|
||||
has_msu1 = file::exists(interface->path(Cartridge::Slot::Base, ".msu"));
|
||||
if(has_msu1) {
|
||||
Mapping m({ &MSU1::mmio_read, &msu1 }, { &MSU1::mmio_write, &msu1 });
|
||||
m.banklo = 0x00, m.bankhi = 0x3f, m.addrlo = 0x2000, m.addrhi = 0x2007;
|
||||
mapping.append(m);
|
||||
m.banklo = 0x80, m.bankhi = 0xbf, m.addrlo = 0x2000, m.addrhi = 0x2007;
|
||||
mapping.append(m);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
has_msu1 = true;
|
||||
|
||||
foreach(node, root) {
|
||||
if(node.name != "map") continue;
|
||||
Mapping m({ &MSU1::mmio_read, &msu1 }, { &MSU1::mmio_write, &msu1 });
|
||||
parse_markup_map(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_link(BML::Node &root) {
|
||||
if(root.exists() == false) return;
|
||||
has_link = true;
|
||||
|
||||
link.frequency = max(1, parse_markup_integer(root["frequency"].value));
|
||||
link.program = root["program"].value;
|
||||
|
||||
foreach(node, root) {
|
||||
if(node.name != "map") continue;
|
||||
Mapping m({ &Link::read, &link }, { &Link::write, &link });
|
||||
parse_markup_map(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
|
||||
Cartridge::Mapping::Mapping() {
|
||||
mode.i = Bus::MapMode::Direct;
|
||||
banklo = bankhi = addrlo = addrhi = offset = size = 0;
|
||||
}
|
||||
|
||||
Cartridge::Mapping::Mapping(Memory &memory) {
|
||||
read = { &Memory::read, &memory };
|
||||
write = { &Memory::write, &memory };
|
||||
mode.i = Bus::MapMode::Direct;
|
||||
banklo = bankhi = addrlo = addrhi = offset = size = 0;
|
||||
}
|
||||
|
||||
Cartridge::Mapping::Mapping(const function<uint8 (unsigned)> &read_, const function<void (unsigned, uint8)> &write_) {
|
||||
read = read_;
|
||||
write = write_;
|
||||
mode.i = Bus::MapMode::Direct;
|
||||
banklo = bankhi = addrlo = addrhi = offset = size = 0;
|
||||
}
|
||||
|
||||
#endif
|
@ -1,7 +1,9 @@
|
||||
#ifdef CARTRIDGE_CPP
|
||||
|
||||
void Cartridge::serialize(serializer &s) {
|
||||
if(ram.data()) s.array(ram.data(), ram.size());
|
||||
foreach(ram, nvram) {
|
||||
if(ram.size) s.array(ram.data, ram.size);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -16,27 +16,22 @@ void Cheat::enable(bool state) {
|
||||
|
||||
void Cheat::synchronize() {
|
||||
memset(override, 0x00, 16 * 1024 * 1024);
|
||||
code_enabled = false;
|
||||
code_enabled = size() > 0;
|
||||
|
||||
for(unsigned i = 0; i < size(); i++) {
|
||||
const CheatCode &code = operator[](i);
|
||||
if(code.enabled == false) continue;
|
||||
|
||||
for(unsigned n = 0; n < code.addr.size(); n++) {
|
||||
code_enabled = true;
|
||||
unsigned addr = mirror(code.addr);
|
||||
override[addr] = true;
|
||||
if((addr & 0xffe000) == 0x7e0000) {
|
||||
//mirror $7e:0000-1fff to $00-3f|80-bf:0000-1fff
|
||||
unsigned mirroraddr;
|
||||
for(unsigned x = 0; x <= 0x3f; x++) {
|
||||
mirroraddr = ((0x00 + x) << 16) + (addr & 0x1fff);
|
||||
override[mirroraddr] = true;
|
||||
|
||||
unsigned addr = mirror(code.addr[n]);
|
||||
override[addr] = true;
|
||||
if((addr & 0xffe000) == 0x7e0000) {
|
||||
//mirror $7e:0000-1fff to $00-3f|80-bf:0000-1fff
|
||||
unsigned mirroraddr;
|
||||
for(unsigned x = 0; x <= 0x3f; x++) {
|
||||
mirroraddr = ((0x00 + x) << 16) + (addr & 0x1fff);
|
||||
override[mirroraddr] = true;
|
||||
|
||||
mirroraddr = ((0x80 + x) << 16) + (addr & 0x1fff);
|
||||
override[mirroraddr] = true;
|
||||
}
|
||||
mirroraddr = ((0x80 + x) << 16) + (addr & 0x1fff);
|
||||
override[mirroraddr] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -49,12 +44,8 @@ uint8 Cheat::read(unsigned addr) const {
|
||||
|
||||
for(unsigned i = 0; i < size(); i++) {
|
||||
const CheatCode &code = operator[](i);
|
||||
if(code.enabled == false) continue;
|
||||
|
||||
for(unsigned n = 0; n < code.addr.size(); n++) {
|
||||
if(addr == mirror(code.addr[n])) {
|
||||
return code.data[n];
|
||||
}
|
||||
if(addr == mirror(code.addr)) {
|
||||
return code.data;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,15 +1,9 @@
|
||||
struct CheatCode {
|
||||
bool enabled;
|
||||
array<unsigned> addr;
|
||||
array<uint8> data;
|
||||
|
||||
bool operator=(string);
|
||||
CheatCode();
|
||||
unsigned addr;
|
||||
unsigned data;
|
||||
};
|
||||
|
||||
class Cheat : public linear_vector<CheatCode> {
|
||||
public:
|
||||
struct Type { enum e { ProActionReplay, GameGenie } i; };
|
||||
struct Cheat : public linear_vector<CheatCode> {
|
||||
uint8 *override;
|
||||
|
||||
bool enabled() const;
|
||||
@ -21,8 +15,7 @@ public:
|
||||
Cheat();
|
||||
~Cheat();
|
||||
|
||||
static bool decode(const char*, unsigned&, uint8&, Type&);
|
||||
static bool encode(string&, unsigned, uint8, Type);
|
||||
static bool decode(const string&, unsigned&, unsigned&);
|
||||
|
||||
private:
|
||||
bool system_enabled;
|
||||
|
@ -4,7 +4,7 @@ void HitachiDSP::serialize(serializer &s) {
|
||||
Processor::serialize(s);
|
||||
|
||||
s.array(dataRAM);
|
||||
foreach(n, stack) s.integer(n);
|
||||
for(auto &n : stack) s.integer(n);
|
||||
s.integer(opcode);
|
||||
|
||||
unsigned state_ = (unsigned)state.i;
|
||||
@ -25,7 +25,7 @@ void HitachiDSP::serialize(serializer &s) {
|
||||
s.integer(regs.ramdata);
|
||||
s.integer(regs.busaddr);
|
||||
s.integer(regs.ramaddr);
|
||||
foreach(n, regs.gpr) s.integer(n);
|
||||
for(auto &n : regs.gpr) s.integer(n);
|
||||
|
||||
s.integer(regs.dma_source);
|
||||
s.integer(regs.dma_length);
|
||||
|
@ -59,8 +59,8 @@ void ICD2::reset() {
|
||||
r7800 = 0x0000;
|
||||
mlt_req = 0;
|
||||
|
||||
foreach(byte, lcd.buffer) byte = 0xff;
|
||||
foreach(byte, lcd.output) byte = 0xff;
|
||||
for(auto &byte : lcd.buffer) byte = 0;
|
||||
for(auto &byte : lcd.output) byte = 0;
|
||||
lcd.row = 0;
|
||||
|
||||
packetsize = 0;
|
||||
@ -69,8 +69,8 @@ void ICD2::reset() {
|
||||
joyp14lock = 0;
|
||||
pulselock = true;
|
||||
|
||||
GameBoy::system.init(this);
|
||||
GameBoy::system.power();
|
||||
GameBoy::Interface::initialize(this);
|
||||
GameBoy::Interface::power();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
#ifdef ICD2_CPP
|
||||
|
||||
//called on rendered lines 0-143 (not on Vblank lines 144-153)
|
||||
void ICD2::lcd_scanline() {
|
||||
void ICD2::lcdScanline() {
|
||||
if((GameBoy::lcd.status.ly & 7) == 0) {
|
||||
lcd.row = (lcd.row + 1) & 3;
|
||||
}
|
||||
@ -10,7 +10,7 @@ void ICD2::lcd_scanline() {
|
||||
memcpy(lcd.buffer + offset, GameBoy::lcd.screen + GameBoy::lcd.status.ly * 160, 160);
|
||||
}
|
||||
|
||||
void ICD2::joyp_write(bool p15, bool p14) {
|
||||
void ICD2::joypWrite(bool p15, bool p14) {
|
||||
//joypad handling
|
||||
if(p15 == 1 && p14 == 1) {
|
||||
if(joyp15lock == 0 && joyp14lock == 0) {
|
||||
@ -80,17 +80,14 @@ void ICD2::joyp_write(bool p15, bool p14) {
|
||||
packetlock = true;
|
||||
}
|
||||
|
||||
void ICD2::video_refresh(const uint8_t *data) {
|
||||
void ICD2::videoRefresh(const uint8_t *data) {
|
||||
}
|
||||
|
||||
void ICD2::audio_sample(int16_t center, int16_t left, int16_t right) {
|
||||
void ICD2::audioSample(int16_t center, int16_t left, int16_t right) {
|
||||
audio.coprocessor_sample(left, right);
|
||||
}
|
||||
|
||||
void ICD2::input_poll() {
|
||||
}
|
||||
|
||||
bool ICD2::input_poll(unsigned id) {
|
||||
bool ICD2::inputPoll(unsigned id) {
|
||||
GameBoy::cpu.status.mlt_req = joyp_id & mlt_req;
|
||||
|
||||
unsigned data = 0x00;
|
||||
|
@ -1,9 +1,8 @@
|
||||
void lcd_scanline();
|
||||
void joyp_write(bool p15, bool p14);
|
||||
void video_refresh(const uint8_t *data);
|
||||
void audio_sample(int16_t center, int16_t left, int16_t right);
|
||||
void input_poll();
|
||||
bool input_poll(unsigned id);
|
||||
void lcdScanline();
|
||||
void joypWrite(bool p15, bool p14);
|
||||
void videoRefresh(const uint8_t *data);
|
||||
void audioSample(int16_t center, int16_t left, int16_t right);
|
||||
bool inputPoll(unsigned id);
|
||||
|
||||
struct Packet {
|
||||
uint8 data[16];
|
||||
|
@ -6,9 +6,7 @@ void ICD2::render(const uint8 *source) {
|
||||
|
||||
for(unsigned y = 0; y < 8; y++) {
|
||||
for(unsigned x = 0; x < 160; x++) {
|
||||
unsigned pixel = *source++ / 0x55;
|
||||
pixel ^= 3;
|
||||
|
||||
unsigned pixel = *source++;
|
||||
unsigned addr = y * 2 + (x / 8 * 16);
|
||||
lcd.output[addr + 0] |= ((pixel & 1) >> 0) << (7 - (x & 7));
|
||||
lcd.output[addr + 1] |= ((pixel & 2) >> 1) << (7 - (x & 7));
|
||||
|
@ -22,7 +22,7 @@ void Link::init() {
|
||||
|
||||
void Link::load() {
|
||||
if(opened()) close();
|
||||
string basename = system.interface->path(Cartridge::Slot::Base, "");
|
||||
string basename = interface->path(Cartridge::Slot::Base, "");
|
||||
string name = program != "" ? program : notdir(basename);
|
||||
string path = dir(basename);
|
||||
if(open(name, path)) {
|
||||
|
@ -50,7 +50,7 @@ void MSU1::init() {
|
||||
|
||||
void MSU1::load() {
|
||||
if(datafile.open()) datafile.close();
|
||||
datafile.open(system.interface->path(Cartridge::Slot::Base, ".msu"), file::mode_read);
|
||||
datafile.open(interface->path(Cartridge::Slot::Base, ".msu"), file::mode_read);
|
||||
}
|
||||
|
||||
void MSU1::unload() {
|
||||
@ -133,7 +133,7 @@ void MSU1::mmio_write(unsigned addr, uint8 data) {
|
||||
if(addr == 0x2005) {
|
||||
mmio.audio_track = (mmio.audio_track & 0x00ff) | (data << 8);
|
||||
if(audiofile.open()) audiofile.close();
|
||||
if(audiofile.open(system.interface->path(Cartridge::Slot::Base, string("-", (unsigned)mmio.audio_track, ".pcm")), file::mode_read)) {
|
||||
if(audiofile.open(interface->path(Cartridge::Slot::Base, string("-", (unsigned)mmio.audio_track, ".pcm")), file::mode_read)) {
|
||||
uint32 header = audiofile.readm(4);
|
||||
if(header != 0x4d535531) { //verify 'MSU1' header
|
||||
audiofile.close();
|
||||
|
@ -16,12 +16,12 @@ void MSU1::serialize(serializer &s) {
|
||||
s.integer(mmio.audio_play);
|
||||
|
||||
if(datafile.open()) datafile.close();
|
||||
if(datafile.open(system.interface->path(Cartridge::Slot::Base, ".msu"), file::mode_read)) {
|
||||
if(datafile.open(interface->path(Cartridge::Slot::Base, ".msu"), file::mode_read)) {
|
||||
datafile.seek(mmio.data_offset);
|
||||
}
|
||||
|
||||
if(audiofile.open()) audiofile.close();
|
||||
if(audiofile.open(system.interface->path(Cartridge::Slot::Base, string("-", (unsigned)mmio.audio_track, ".pcm")), file::mode_read)) {
|
||||
if(audiofile.open(interface->path(Cartridge::Slot::Base, string("-", (unsigned)mmio.audio_track, ".pcm")), file::mode_read)) {
|
||||
audiofile.seek(mmio.audio_offset);
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,8 @@ void SA1::enter() {
|
||||
|
||||
if(status.interrupt_pending) {
|
||||
status.interrupt_pending = false;
|
||||
interrupt(status.interrupt_vector);
|
||||
op_irq();
|
||||
continue;
|
||||
}
|
||||
|
||||
(this->*opcode_table[op_readpc()])();
|
||||
@ -38,43 +39,30 @@ void SA1::enter() {
|
||||
void SA1::last_cycle() {
|
||||
if(mmio.sa1_nmi && !mmio.sa1_nmicl) {
|
||||
status.interrupt_pending = true;
|
||||
status.interrupt_vector = mmio.cnv;
|
||||
regs.vector = mmio.cnv;
|
||||
mmio.sa1_nmifl = true;
|
||||
mmio.sa1_nmicl = 1;
|
||||
regs.wai = false;
|
||||
} else if(!regs.p.i) {
|
||||
if(mmio.timer_irqen && !mmio.timer_irqcl) {
|
||||
status.interrupt_pending = true;
|
||||
status.interrupt_vector = mmio.civ;
|
||||
regs.vector = mmio.civ;
|
||||
mmio.timer_irqfl = true;
|
||||
regs.wai = false;
|
||||
} else if(mmio.dma_irqen && !mmio.dma_irqcl) {
|
||||
status.interrupt_pending = true;
|
||||
status.interrupt_vector = mmio.civ;
|
||||
regs.vector = mmio.civ;
|
||||
mmio.dma_irqfl = true;
|
||||
regs.wai = false;
|
||||
} else if(mmio.sa1_irq && !mmio.sa1_irqcl) {
|
||||
status.interrupt_pending = true;
|
||||
status.interrupt_vector = mmio.civ;
|
||||
regs.vector = mmio.civ;
|
||||
mmio.sa1_irqfl = true;
|
||||
regs.wai = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SA1::interrupt(uint16 vector) {
|
||||
SA1::op_read(regs.pc.d);
|
||||
SA1::op_io();
|
||||
if(!regs.e) op_writestack(regs.pc.b);
|
||||
op_writestack(regs.pc.h);
|
||||
op_writestack(regs.pc.l);
|
||||
op_writestack(regs.e ? (regs.p & ~0x10) : regs.p);
|
||||
regs.pc.w = vector;
|
||||
regs.pc.b = 0x00;
|
||||
regs.p.i = 1;
|
||||
regs.p.d = 0;
|
||||
}
|
||||
|
||||
bool SA1::interrupt_pending() {
|
||||
return status.interrupt_pending;
|
||||
}
|
||||
@ -138,22 +126,22 @@ void SA1::reset() {
|
||||
iram.write(addr, 0x00);
|
||||
}
|
||||
|
||||
regs.pc.d = 0x000000;
|
||||
regs.x.h = 0x00;
|
||||
regs.y.h = 0x00;
|
||||
regs.s.h = 0x01;
|
||||
regs.d = 0x0000;
|
||||
regs.db = 0x00;
|
||||
regs.p = 0x34;
|
||||
regs.e = 1;
|
||||
regs.mdr = 0x00;
|
||||
regs.wai = false;
|
||||
regs.pc.d = 0x000000;
|
||||
regs.x.h = 0x00;
|
||||
regs.y.h = 0x00;
|
||||
regs.s.h = 0x01;
|
||||
regs.d = 0x0000;
|
||||
regs.db = 0x00;
|
||||
regs.p = 0x34;
|
||||
regs.e = 1;
|
||||
regs.mdr = 0x00;
|
||||
regs.wai = false;
|
||||
regs.vector = 0x0000;
|
||||
CPUcore::update_table();
|
||||
|
||||
status.tick_counter = 0;
|
||||
|
||||
status.interrupt_pending = false;
|
||||
status.interrupt_vector = 0x0000;
|
||||
|
||||
status.scanlines = (system.region.i == System::Region::NTSC ? 262 : 312);
|
||||
status.vcounter = 0;
|
||||
|
@ -9,7 +9,6 @@ public:
|
||||
uint8 tick_counter;
|
||||
|
||||
bool interrupt_pending;
|
||||
uint16 interrupt_vector;
|
||||
|
||||
uint16 scanlines;
|
||||
uint16 vcounter;
|
||||
@ -18,7 +17,6 @@ public:
|
||||
|
||||
static void Enter();
|
||||
void enter();
|
||||
void interrupt(uint16 vector);
|
||||
void tick();
|
||||
|
||||
alwaysinline void trigger_irq();
|
||||
|
@ -8,7 +8,6 @@ void SA1::serialize(serializer &s) {
|
||||
s.integer(status.tick_counter);
|
||||
|
||||
s.integer(status.interrupt_pending);
|
||||
s.integer(status.interrupt_vector);
|
||||
|
||||
s.integer(status.scanlines);
|
||||
s.integer(status.vcounter);
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
uint2 Gamepad::data() {
|
||||
if(counter >= 16) return 1;
|
||||
uint2 result = system.interface->input_poll(port, Input::Device::Joypad, 0, counter);
|
||||
uint2 result = interface->inputPoll(port, Input::Device::Joypad, 0, counter);
|
||||
if(latched == 0) counter++;
|
||||
return result;
|
||||
}
|
||||
|
@ -18,16 +18,16 @@ void Justifier::enter() {
|
||||
}
|
||||
|
||||
if(next < prev) {
|
||||
int nx1 = system.interface->input_poll(port, Input::Device::Justifier, 0, (unsigned)Input::JustifierID::X);
|
||||
int ny1 = system.interface->input_poll(port, Input::Device::Justifier, 0, (unsigned)Input::JustifierID::Y);
|
||||
int nx1 = interface->inputPoll(port, Input::Device::Justifier, 0, (unsigned)Input::JustifierID::X);
|
||||
int ny1 = interface->inputPoll(port, Input::Device::Justifier, 0, (unsigned)Input::JustifierID::Y);
|
||||
nx1 += x1;
|
||||
ny1 += y1;
|
||||
x1 = max(-16, min(256 + 16, nx1));
|
||||
y1 = max(-16, min(240 + 16, ny1));
|
||||
|
||||
if(chained == true) {
|
||||
int nx2 = system.interface->input_poll(port, Input::Device::Justifiers, 1, (unsigned)Input::JustifierID::X);
|
||||
int ny2 = system.interface->input_poll(port, Input::Device::Justifiers, 1, (unsigned)Input::JustifierID::Y);
|
||||
int nx2 = interface->inputPoll(port, Input::Device::Justifiers, 1, (unsigned)Input::JustifierID::X);
|
||||
int ny2 = interface->inputPoll(port, Input::Device::Justifiers, 1, (unsigned)Input::JustifierID::Y);
|
||||
nx2 += x2;
|
||||
ny2 += y2;
|
||||
x2 = max(-16, min(256 + 16, nx2));
|
||||
@ -48,11 +48,11 @@ uint2 Justifier::data() {
|
||||
if(counter >= 32) return 1;
|
||||
|
||||
if(counter == 0) {
|
||||
trigger1 = system.interface->input_poll(port, Input::Device::Justifier, 0, (unsigned)Input::JustifierID::Trigger);
|
||||
start1 = system.interface->input_poll(port, Input::Device::Justifier, 0, (unsigned)Input::JustifierID::Start);
|
||||
trigger1 = interface->inputPoll(port, Input::Device::Justifier, 0, (unsigned)Input::JustifierID::Trigger);
|
||||
start1 = interface->inputPoll(port, Input::Device::Justifier, 0, (unsigned)Input::JustifierID::Start);
|
||||
if(chained) {
|
||||
trigger2 = system.interface->input_poll(port, Input::Device::Justifiers, 1, (unsigned)Input::JustifierID::Trigger);
|
||||
start2 = system.interface->input_poll(port, Input::Device::Justifiers, 1, (unsigned)Input::JustifierID::Start);
|
||||
trigger2 = interface->inputPoll(port, Input::Device::Justifiers, 1, (unsigned)Input::JustifierID::Trigger);
|
||||
start2 = interface->inputPoll(port, Input::Device::Justifiers, 1, (unsigned)Input::JustifierID::Start);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,8 +3,8 @@
|
||||
uint2 Mouse::data() {
|
||||
if(counter >= 32) return 1;
|
||||
|
||||
int position_x = system.interface->input_poll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::X); //-n = left, 0 = center, +n = right
|
||||
int position_y = system.interface->input_poll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Y); //-n = up, 0 = center, +n = down
|
||||
int position_x = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::X); //-n = left, 0 = center, +n = right
|
||||
int position_y = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Y); //-n = up, 0 = center, +n = down
|
||||
|
||||
bool direction_x = position_x < 0; //0 = right, 1 = left
|
||||
bool direction_y = position_y < 0; //0 = down, 1 = up
|
||||
@ -25,8 +25,8 @@ uint2 Mouse::data() {
|
||||
case 6: return 0;
|
||||
case 7: return 0;
|
||||
|
||||
case 8: return system.interface->input_poll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Right);
|
||||
case 9: return system.interface->input_poll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Left);
|
||||
case 8: return interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Right);
|
||||
case 9: return interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Left);
|
||||
case 10: return 0; //speed (0 = slow, 1 = normal, 2 = fast, 3 = unused)
|
||||
case 11: return 0; // ||
|
||||
|
||||
|
@ -18,8 +18,8 @@ uint2 Multitap::data() {
|
||||
port2 = 3; //controller 4
|
||||
}
|
||||
|
||||
bool data1 = system.interface->input_poll(port, Input::Device::Multitap, port1, index);
|
||||
bool data2 = system.interface->input_poll(port, Input::Device::Multitap, port2, index);
|
||||
bool data1 = interface->inputPoll(port, Input::Device::Multitap, port1, index);
|
||||
bool data2 = interface->inputPoll(port, Input::Device::Multitap, port2, index);
|
||||
return (data2 << 1) | (data1 << 0);
|
||||
}
|
||||
|
||||
|
@ -79,7 +79,7 @@ void Serial::latch(bool data) {
|
||||
|
||||
Serial::Serial(bool port) : Controller(port) {
|
||||
enable = false;
|
||||
string basename = system.interface->path(Cartridge::Slot::Base, "");
|
||||
string basename = interface->path(Cartridge::Slot::Base, "");
|
||||
string name = notdir(basename);
|
||||
string path = dir(basename);
|
||||
if(open(name, path)) {
|
||||
|
@ -28,8 +28,8 @@ void SuperScope::enter() {
|
||||
|
||||
if(next < prev) {
|
||||
//Vcounter wrapped back to zero; update cursor coordinates for start of new frame
|
||||
int nx = system.interface->input_poll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::X);
|
||||
int ny = system.interface->input_poll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::Y);
|
||||
int nx = interface->inputPoll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::X);
|
||||
int ny = interface->inputPoll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::Y);
|
||||
nx += x;
|
||||
ny += y;
|
||||
x = max(-16, min(256 + 16, nx));
|
||||
@ -51,7 +51,7 @@ uint2 SuperScope::data() {
|
||||
|
||||
if(counter == 0) {
|
||||
//turbo is a switch; toggle is edge sensitive
|
||||
bool newturbo = system.interface->input_poll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::Turbo);
|
||||
bool newturbo = interface->inputPoll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::Turbo);
|
||||
if(newturbo && !turbo) {
|
||||
turbo = !turbo; //toggle state
|
||||
turbolock = true;
|
||||
@ -62,7 +62,7 @@ uint2 SuperScope::data() {
|
||||
//trigger is a button
|
||||
//if turbo is active, trigger is level sensitive; otherwise, it is edge sensitive
|
||||
trigger = false;
|
||||
bool newtrigger = system.interface->input_poll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::Trigger);
|
||||
bool newtrigger = interface->inputPoll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::Trigger);
|
||||
if(newtrigger && (turbo || !triggerlock)) {
|
||||
trigger = true;
|
||||
triggerlock = true;
|
||||
@ -71,11 +71,11 @@ uint2 SuperScope::data() {
|
||||
}
|
||||
|
||||
//cursor is a button; it is always level sensitive
|
||||
cursor = system.interface->input_poll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::Cursor);
|
||||
cursor = interface->inputPoll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::Cursor);
|
||||
|
||||
//pause is a button; it is always edge sensitive
|
||||
pause = false;
|
||||
bool newpause = system.interface->input_poll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::Pause);
|
||||
bool newpause = interface->inputPoll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::Pause);
|
||||
if(newpause && !pauselock) {
|
||||
pause = true;
|
||||
pauselock = true;
|
||||
|
@ -67,6 +67,21 @@ alwaysinline void CPUcore::op_io_cond6(uint16 addr) {
|
||||
}
|
||||
}
|
||||
|
||||
void CPUcore::op_irq() {
|
||||
op_read(regs.pc.d);
|
||||
op_io();
|
||||
if(!regs.e) op_writestack(regs.pc.b);
|
||||
op_writestack(regs.pc.h);
|
||||
op_writestack(regs.pc.l);
|
||||
op_writestack(regs.e ? (regs.p & ~0x10) : regs.p);
|
||||
rd.l = op_read(regs.vector + 0);
|
||||
regs.pc.b = 0x00;
|
||||
regs.p.i = 1;
|
||||
regs.p.d = 0;
|
||||
rd.h = op_read(regs.vector + 1);
|
||||
regs.pc.w = rd.w;
|
||||
}
|
||||
|
||||
CPUcore::CPUcore() {
|
||||
initialize_opcode_table();
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
class CPUcore {
|
||||
public:
|
||||
struct CPUcore {
|
||||
#include "registers.hpp"
|
||||
#include "memory.hpp"
|
||||
#include "disassembler/disassembler.hpp"
|
||||
@ -19,6 +18,8 @@ public:
|
||||
void op_io_cond4(uint16 x, uint16 y);
|
||||
void op_io_cond6(uint16 addr);
|
||||
|
||||
void op_irq();
|
||||
|
||||
void op_adc_b();
|
||||
void op_adc_w();
|
||||
void op_and_b();
|
||||
|
@ -71,11 +71,13 @@ struct regs_t {
|
||||
uint8 db;
|
||||
bool e;
|
||||
|
||||
bool irq; //IRQ pin (0 = low, 1 = trigger)
|
||||
bool wai; //raised during wai, cleared after interrupt triggered
|
||||
uint8 mdr; //memory data register
|
||||
bool irq; //IRQ pin (0 = low, 1 = trigger)
|
||||
bool wai; //raised during wai, cleared after interrupt triggered
|
||||
uint8 mdr; //memory data register
|
||||
uint16 vector; //interrupt vector address
|
||||
|
||||
regs_t() : a(r[0]), x(r[1]), y(r[2]), z(r[3]), s(r[4]), d(r[5]), db(0), e(false), irq(false), wai(false), mdr(0) {
|
||||
regs_t():
|
||||
a(r[0]), x(r[1]), y(r[2]), z(r[3]), s(r[4]), d(r[5]), db(0), e(false), irq(false), wai(false), mdr(0), vector(0) {
|
||||
z = 0;
|
||||
}
|
||||
};
|
||||
|
@ -24,6 +24,7 @@ void CPUcore::core_serialize(serializer &s) {
|
||||
s.integer(regs.irq);
|
||||
s.integer(regs.wai);
|
||||
s.integer(regs.mdr);
|
||||
s.integer(regs.vector);
|
||||
|
||||
s.integer(aa.d);
|
||||
s.integer(rd.d);
|
||||
|
@ -69,11 +69,11 @@ void CPU::enter() {
|
||||
status.interrupt_pending = false;
|
||||
if(status.nmi_pending) {
|
||||
status.nmi_pending = false;
|
||||
status.interrupt_vector = (regs.e == false ? 0xffea : 0xfffa);
|
||||
regs.vector = (regs.e == false ? 0xffea : 0xfffa);
|
||||
op_irq();
|
||||
} else if(status.irq_pending) {
|
||||
status.irq_pending = false;
|
||||
status.interrupt_vector = (regs.e == false ? 0xffee : 0xfffe);
|
||||
regs.vector = (regs.e == false ? 0xffee : 0xfffe);
|
||||
op_irq();
|
||||
} else if(status.reset_pending) {
|
||||
status.reset_pending = false;
|
||||
@ -91,21 +91,6 @@ void CPU::op_step() {
|
||||
(this->*opcode_table[op_readpc()])();
|
||||
}
|
||||
|
||||
void CPU::op_irq() {
|
||||
op_read(regs.pc.d);
|
||||
op_io();
|
||||
if(!regs.e) op_writestack(regs.pc.b);
|
||||
op_writestack(regs.pc.h);
|
||||
op_writestack(regs.pc.l);
|
||||
op_writestack(regs.e ? (regs.p & ~0x10) : regs.p);
|
||||
rd.l = op_read(status.interrupt_vector + 0);
|
||||
regs.pc.b = 0x00;
|
||||
regs.p.i = 1;
|
||||
regs.p.d = 0;
|
||||
rd.h = op_read(status.interrupt_vector + 1);
|
||||
regs.pc.w = rd.w;
|
||||
}
|
||||
|
||||
static uint8 cpu_default_read(unsigned addr) {
|
||||
return cpu.wram[addr];
|
||||
}
|
||||
@ -140,7 +125,7 @@ void CPU::enable() {
|
||||
|
||||
void CPU::power() {
|
||||
cpu_version = config.cpu.version;
|
||||
foreach(n, wram) n = random(config.cpu.wram_init_value);
|
||||
for(auto &n : wram) n = random(config.cpu.wram_init_value);
|
||||
|
||||
regs.a = regs.x = regs.y = 0x0000;
|
||||
regs.s = 0x01ff;
|
||||
@ -158,16 +143,17 @@ void CPU::reset() {
|
||||
PPUcounter::reset();
|
||||
|
||||
//note: some registers are not fully reset by SNES
|
||||
regs.pc = 0x000000;
|
||||
regs.x.h = 0x00;
|
||||
regs.y.h = 0x00;
|
||||
regs.s.h = 0x01;
|
||||
regs.d = 0x0000;
|
||||
regs.db = 0x00;
|
||||
regs.p = 0x34;
|
||||
regs.e = 1;
|
||||
regs.mdr = 0x00;
|
||||
regs.wai = false;
|
||||
regs.pc = 0x000000;
|
||||
regs.x.h = 0x00;
|
||||
regs.y.h = 0x00;
|
||||
regs.s.h = 0x01;
|
||||
regs.d = 0x0000;
|
||||
regs.db = 0x00;
|
||||
regs.p = 0x34;
|
||||
regs.e = 1;
|
||||
regs.mdr = 0x00;
|
||||
regs.wai = false;
|
||||
regs.vector = 0xfffc; //reset vector address
|
||||
update_table();
|
||||
|
||||
mmio_reset();
|
||||
|
@ -1,5 +1,4 @@
|
||||
class CPU : public Processor, public CPUcore, public PPUcounter {
|
||||
public:
|
||||
struct CPU : public Processor, public CPUcore, public PPUcounter {
|
||||
uint8 wram[128 * 1024];
|
||||
|
||||
enum{ Threaded = true };
|
||||
@ -36,7 +35,6 @@ private:
|
||||
|
||||
struct Status {
|
||||
bool interrupt_pending;
|
||||
uint16 interrupt_vector;
|
||||
|
||||
unsigned clock_count;
|
||||
unsigned line_clocks;
|
||||
@ -133,7 +131,6 @@ private:
|
||||
} alu;
|
||||
|
||||
static void Enter();
|
||||
void op_irq();
|
||||
debugvirtual void op_step();
|
||||
|
||||
friend class CPUDebugger;
|
||||
|
@ -352,7 +352,7 @@ void CPU::mmio_power() {
|
||||
|
||||
void CPU::mmio_reset() {
|
||||
//$2140-217f
|
||||
foreach(port, status.port) port = 0x00;
|
||||
for(auto &port : status.port) port = 0x00;
|
||||
|
||||
//$2181-$2183
|
||||
status.wram_addr = 0x000000;
|
||||
|
@ -10,7 +10,6 @@ void CPU::serialize(serializer &s) {
|
||||
s.integer(cpu_version);
|
||||
|
||||
s.integer(status.interrupt_pending);
|
||||
s.integer(status.interrupt_vector);
|
||||
|
||||
s.integer(status.clock_count);
|
||||
s.integer(status.line_clocks);
|
||||
|
@ -182,7 +182,6 @@ void CPU::timing_reset() {
|
||||
|
||||
status.reset_pending = true;
|
||||
status.interrupt_pending = true;
|
||||
status.interrupt_vector = 0xfffc; //reset vector address
|
||||
|
||||
status.dma_active = false;
|
||||
status.dma_counter = 0;
|
||||
|
@ -1,5 +1,4 @@
|
||||
class Debugger {
|
||||
public:
|
||||
struct Debugger {
|
||||
struct BreakEvent{ enum e{
|
||||
None,
|
||||
BreakpointHit,
|
||||
|
@ -1,6 +1,5 @@
|
||||
class DSP : public Processor {
|
||||
public:
|
||||
enum{ Threaded = true };
|
||||
struct DSP : public Processor {
|
||||
enum { Threaded = true };
|
||||
alwaysinline void step(unsigned clocks);
|
||||
alwaysinline void synchronize_smp();
|
||||
|
||||
|
@ -26,7 +26,7 @@ void Input::connect(bool port, Input::Device::e id) {
|
||||
}
|
||||
}
|
||||
|
||||
Input::Input() {
|
||||
Input::Input() : port1(0), port2(0) {
|
||||
connect(Controller::Port1, Input::Device::Joypad);
|
||||
connect(Controller::Port2, Input::Device::Joypad);
|
||||
}
|
||||
|
122
snes/interface/interface.cpp
Normal file
122
snes/interface/interface.cpp
Normal file
@ -0,0 +1,122 @@
|
||||
#include <snes/snes.hpp>
|
||||
|
||||
namespace SNES {
|
||||
|
||||
Interface *interface = 0;
|
||||
|
||||
void Interface::videoRefresh(const uint32_t *data, bool hires, bool interlace, bool overscan) {
|
||||
}
|
||||
|
||||
void Interface::audioSample(int16_t l_sample, int16_t r_sample) {
|
||||
}
|
||||
|
||||
int16_t Interface::inputPoll(bool port, Input::Device::e device, unsigned index, unsigned id) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Interface::initialize(Interface *derived_interface) {
|
||||
interface = derived_interface;
|
||||
system.init();
|
||||
}
|
||||
|
||||
void Interface::connect(bool port, Input::Device::e device) {
|
||||
input.connect(port, device);
|
||||
}
|
||||
|
||||
bool Interface::cartridgeLoaded() {
|
||||
return cartridge.loaded();
|
||||
}
|
||||
|
||||
void Interface::loadCartridge(const CartridgeData &base) {
|
||||
cartridge.rom.copy(base.data, base.size);
|
||||
cartridge.load(Cartridge::Mode::Normal, base.markup);
|
||||
system.power();
|
||||
}
|
||||
|
||||
void Interface::loadSatellaviewSlottedCartridge(const CartridgeData &base, const CartridgeData &slot) {
|
||||
cartridge.rom.copy(base.data, base.size);
|
||||
if(slot.data) bsxflash.memory.copy(slot.data, slot.size);
|
||||
cartridge.load(Cartridge::Mode::BsxSlotted, base.markup);
|
||||
system.power();
|
||||
}
|
||||
|
||||
void Interface::loadSatellaviewCartridge(const CartridgeData &base, const CartridgeData &slot) {
|
||||
cartridge.rom.copy(base.data, base.size);
|
||||
if(slot.data) bsxflash.memory.copy(slot.data, slot.size);
|
||||
cartridge.load(Cartridge::Mode::Bsx, base.markup);
|
||||
system.power();
|
||||
}
|
||||
|
||||
void Interface::loadSufamiTurboCartridge(const CartridgeData &base, const CartridgeData &slotA, const CartridgeData &slotB) {
|
||||
cartridge.rom.copy(base.data, base.size);
|
||||
if(slotA.data) sufamiturbo.slotA.rom.copy(slotA.data, slotA.size);
|
||||
if(slotB.data) sufamiturbo.slotB.rom.copy(slotB.data, slotB.size);
|
||||
cartridge.load(Cartridge::Mode::SufamiTurbo, base.markup);
|
||||
system.power();
|
||||
}
|
||||
|
||||
void Interface::loadSuperGameBoyCartridge(const CartridgeData &base, const CartridgeData &slot) {
|
||||
cartridge.rom.copy(base.data, base.size);
|
||||
GameBoy::cartridge.load(slot.markup, slot.data, slot.size);
|
||||
cartridge.load(Cartridge::Mode::SuperGameBoy, base.markup);
|
||||
system.power();
|
||||
}
|
||||
|
||||
void Interface::unloadCartridge() {
|
||||
cartridge.unload();
|
||||
}
|
||||
|
||||
Cartridge::Information& Interface::information() {
|
||||
return cartridge.information;
|
||||
}
|
||||
|
||||
linear_vector<Cartridge::NonVolatileRAM>& Interface::memory() {
|
||||
return cartridge.nvram;
|
||||
}
|
||||
|
||||
void Interface::power() {
|
||||
system.power();
|
||||
}
|
||||
|
||||
void Interface::reset() {
|
||||
system.reset();
|
||||
}
|
||||
|
||||
void Interface::run() {
|
||||
system.run();
|
||||
}
|
||||
|
||||
serializer Interface::serialize() {
|
||||
system.runtosave();
|
||||
return system.serialize();
|
||||
}
|
||||
|
||||
bool Interface::unserialize(serializer &s) {
|
||||
return system.unserialize(s);
|
||||
}
|
||||
|
||||
void Interface::setCheats(const lstring &list) {
|
||||
if(cartridge.mode.i == Cartridge::Mode::SuperGameBoy) {
|
||||
return icd2.setCheats(list);
|
||||
}
|
||||
|
||||
cheat.reset();
|
||||
foreach(code, list) {
|
||||
lstring codelist;
|
||||
codelist.split("+", code);
|
||||
foreach(part, codelist) {
|
||||
unsigned addr, data;
|
||||
if(Cheat::decode(part, addr, data)) {
|
||||
CheatCode code = {addr, data};
|
||||
cheat.append(code);
|
||||
}
|
||||
}
|
||||
}
|
||||
cheat.synchronize();
|
||||
}
|
||||
|
||||
void Interface::message(const string &text) {
|
||||
print(text, "\n");
|
||||
}
|
||||
|
||||
}
|
@ -1,23 +1,40 @@
|
||||
#ifndef SNES_INTERFACE_HPP
|
||||
#define SNES_INTERFACE_HPP
|
||||
|
||||
#include <snes/libsnes/libsnes.hpp>
|
||||
|
||||
struct Interface {
|
||||
Interface();
|
||||
virtual void videoRefresh(const uint32_t *data, bool hires, bool interlace, bool overscan);
|
||||
virtual void audioSample(int16_t lsample, int16_t rsample);
|
||||
virtual int16_t inputPoll(bool port, Input::Device::e device, unsigned index, unsigned id);
|
||||
|
||||
void video_refresh(const uint16_t *data, bool hires, bool interlace, bool overscan);
|
||||
void audio_sample(int16_t l_sample, int16_t r_sample);
|
||||
int16_t input_poll(bool port, Input::Device::e device, unsigned index, unsigned id);
|
||||
virtual void initialize(Interface*);
|
||||
|
||||
void message(const string &text);
|
||||
string path(Cartridge::Slot::e slot, const string &hint);
|
||||
virtual void connect(bool port, Input::Device::e device);
|
||||
|
||||
snes_video_refresh_t pvideo_refresh;
|
||||
snes_audio_sample_t paudio_sample;
|
||||
snes_input_poll_t pinput_poll;
|
||||
snes_input_state_t pinput_state;
|
||||
string basename;
|
||||
struct CartridgeData {
|
||||
string markup;
|
||||
const uint8_t *data;
|
||||
unsigned size;
|
||||
};
|
||||
|
||||
virtual bool cartridgeLoaded();
|
||||
virtual void loadCartridge(const CartridgeData &base);
|
||||
virtual void loadSatellaviewSlottedCartridge(const CartridgeData &base, const CartridgeData &slot);
|
||||
virtual void loadSatellaviewCartridge(const CartridgeData &base, const CartridgeData &slot);
|
||||
virtual void loadSufamiTurboCartridge(const CartridgeData &base, const CartridgeData &slotA, const CartridgeData &slotB);
|
||||
virtual void loadSuperGameBoyCartridge(const CartridgeData &base, const CartridgeData &slot);
|
||||
virtual void unloadCartridge();
|
||||
|
||||
Cartridge::Information& information();
|
||||
linear_vector<Cartridge::NonVolatileRAM>& memory();
|
||||
|
||||
virtual void power();
|
||||
virtual void reset();
|
||||
virtual void run();
|
||||
|
||||
virtual serializer serialize();
|
||||
virtual bool unserialize(serializer&);
|
||||
|
||||
void setCheats(const lstring &list = lstring());
|
||||
|
||||
virtual string path(Cartridge::Slot::e slot, const string &hint) = 0;
|
||||
virtual void message(const string &text);
|
||||
};
|
||||
|
||||
#endif
|
||||
extern Interface *interface;
|
||||
|
@ -5,40 +5,81 @@
|
||||
#include <nall/gameboy/cartridge.hpp>
|
||||
using namespace nall;
|
||||
|
||||
void SNES::Interface::video_refresh(const uint16_t *data, bool hires, bool interlace, bool overscan) {
|
||||
unsigned width = hires ? 512 : 256;
|
||||
unsigned height = overscan ? 239 : 224;
|
||||
if(interlace) height <<= 1;
|
||||
data += 9 * 1024; //skip front porch
|
||||
pvideo_refresh(data, width, height);
|
||||
pinput_poll();
|
||||
}
|
||||
struct Interface : public SNES::Interface {
|
||||
snes_video_refresh_t pvideo_refresh;
|
||||
snes_audio_sample_t paudio_sample;
|
||||
snes_input_poll_t pinput_poll;
|
||||
snes_input_state_t pinput_state;
|
||||
string basename;
|
||||
uint16_t *buffer;
|
||||
uint32_t *palette;
|
||||
|
||||
void SNES::Interface::audio_sample(int16_t left, int16_t right) {
|
||||
return paudio_sample(left, right);
|
||||
}
|
||||
void videoRefresh(const uint32_t *data, bool hires, bool interlace, bool overscan) {
|
||||
unsigned width = hires ? 512 : 256;
|
||||
unsigned height = overscan ? 239 : 224;
|
||||
unsigned pitch = 1024 >> interlace;
|
||||
if(interlace) height <<= 1;
|
||||
data += 9 * 1024; //skip front porch
|
||||
|
||||
int16_t SNES::Interface::input_poll(bool port, SNES::Input::Device::e device, unsigned index, unsigned id) {
|
||||
if (id > 11) // Core queries for bit 12-15 as well. Not good ;D
|
||||
return 0;
|
||||
return pinput_state(port, (unsigned)device, index, id);
|
||||
}
|
||||
for(unsigned y = 0; y < height; y++) {
|
||||
const uint32_t *sp = data + y * pitch;
|
||||
uint16_t *dp = buffer + y * pitch;
|
||||
for(unsigned x = 0; x < width; x++) {
|
||||
*dp++ = palette[*sp++];
|
||||
}
|
||||
}
|
||||
|
||||
void SNES::Interface::message(const string &text) {
|
||||
fprintf(stderr, "%s\n", (const char*)text);
|
||||
}
|
||||
if(pvideo_refresh) pvideo_refresh(buffer, width, height);
|
||||
if(pinput_poll) pinput_poll();
|
||||
}
|
||||
|
||||
string SNES::Interface::path(SNES::Cartridge::Slot::e slot, const string &hint) {
|
||||
return string(basename, hint);
|
||||
}
|
||||
void audioSample(int16_t left, int16_t right) {
|
||||
if(paudio_sample) return paudio_sample(left, right);
|
||||
}
|
||||
|
||||
SNES::Interface::Interface() : pvideo_refresh(0), paudio_sample(0), pinput_poll(0), pinput_state(0) {}
|
||||
int16_t inputPoll(bool port, SNES::Input::Device device, unsigned index, unsigned id) {
|
||||
if(pinput_state) return pinput_state(port, (unsigned)device, index, id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SNES::Interface interface;
|
||||
void message(const string &text) {
|
||||
print(text, "\n");
|
||||
}
|
||||
|
||||
string path(SNES::Cartridge::Slot slot, const string &hint) {
|
||||
return { basename, hint };
|
||||
}
|
||||
|
||||
Interface() : pvideo_refresh(0), paudio_sample(0), pinput_poll(0), pinput_state(0) {
|
||||
buffer = new uint16_t[512 * 480];
|
||||
palette = new uint32_t[16 * 32768];
|
||||
|
||||
//{llll bbbbb ggggg rrrrr} -> { rrrrr ggggg bbbbb }
|
||||
for(unsigned l = 0; l < 16; l++) {
|
||||
for(unsigned r = 0; r < 32; r++) {
|
||||
for(unsigned g = 0; g < 32; g++) {
|
||||
for(unsigned b = 0; b < 32; b++) {
|
||||
double luma = (double)l / 15.0;
|
||||
unsigned ar = (luma * r + 0.5);
|
||||
unsigned ag = (luma * g + 0.5);
|
||||
unsigned ab = (luma * b + 0.5);
|
||||
palette[(l << 15) + (r << 10) + (g << 5) + (b << 0)] = (ab << 10) + (ag << 5) + (ar << 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~Interface() {
|
||||
delete[] buffer;
|
||||
delete[] palette;
|
||||
}
|
||||
};
|
||||
|
||||
static Interface interface;
|
||||
|
||||
const char* snes_library_id(void) {
|
||||
static string id(SNES::Info::Name, " (", SNES::Info::Profile, ") v", SNES::Info::Version);
|
||||
return (const char*)id;
|
||||
return "bsnes v083";
|
||||
}
|
||||
|
||||
unsigned snes_library_revision_major(void) {
|
||||
@ -66,7 +107,7 @@ void snes_set_input_state(snes_input_state_t input_state) {
|
||||
}
|
||||
|
||||
void snes_set_controller_port_device(bool port, unsigned device) {
|
||||
SNES::input.connect(port, (SNES::Input::Device::e)device);
|
||||
SNES::input.connect(port, (SNES::Input::Device)device);
|
||||
}
|
||||
|
||||
void snes_set_cartridge_basename(const char *basename) {
|
||||
@ -74,9 +115,9 @@ void snes_set_cartridge_basename(const char *basename) {
|
||||
}
|
||||
|
||||
void snes_init(void) {
|
||||
SNES::system.init(&interface);
|
||||
SNES::input.connect(0, SNES::Input::Device::Joypad);
|
||||
SNES::input.connect(1, SNES::Input::Device::Joypad);
|
||||
interface.initialize(&interface);
|
||||
SNES::input.connect(SNES::Controller::Port1, SNES::Input::Device::Joypad);
|
||||
SNES::input.connect(SNES::Controller::Port2, SNES::Input::Device::Joypad);
|
||||
}
|
||||
|
||||
void snes_term(void) {
|
||||
@ -96,7 +137,7 @@ void snes_run(void) {
|
||||
}
|
||||
|
||||
unsigned snes_serialize_size(void) {
|
||||
return SNES::system.serialize_size;
|
||||
return SNES::system.serialize_size();
|
||||
}
|
||||
|
||||
bool snes_serialize(uint8_t *data, unsigned size) {
|
||||
@ -112,15 +153,27 @@ bool snes_unserialize(const uint8_t *data, unsigned size) {
|
||||
return SNES::system.unserialize(s);
|
||||
}
|
||||
|
||||
struct CheatList {
|
||||
bool enable;
|
||||
string code;
|
||||
CheatList() : enable(false) {}
|
||||
};
|
||||
|
||||
static linear_vector<CheatList> cheatList;
|
||||
|
||||
void snes_cheat_reset(void) {
|
||||
SNES::cheat.reset();
|
||||
SNES::cheat.synchronize();
|
||||
cheatList.reset();
|
||||
interface.setCheats();
|
||||
}
|
||||
|
||||
void snes_cheat_set(unsigned index, bool enabled, const char *code) {
|
||||
SNES::cheat[index] = code;
|
||||
SNES::cheat[index].enabled = enabled;
|
||||
SNES::cheat.synchronize();
|
||||
void snes_cheat_set(unsigned index, bool enable, const char *code) {
|
||||
cheatList[index].enable = enable;
|
||||
cheatList[index].code = code;
|
||||
lstring list;
|
||||
for(unsigned n = 0; n < cheatList.size(); n++) {
|
||||
if(cheatList[n].enable) list.append(cheatList[n].code);
|
||||
}
|
||||
interface.setCheats(list);
|
||||
}
|
||||
|
||||
bool snes_load_cartridge_normal(
|
||||
@ -128,8 +181,8 @@ bool snes_load_cartridge_normal(
|
||||
) {
|
||||
snes_cheat_reset();
|
||||
if(rom_data) SNES::cartridge.rom.copy(rom_data, rom_size);
|
||||
string xmlrom = (rom_xml && *rom_xml) ? string(rom_xml) : SNESCartridge(rom_data, rom_size).xmlMemoryMap;
|
||||
SNES::cartridge.load(SNES::Cartridge::Mode::Normal, lstring( xmlrom ));
|
||||
string xmlrom = (rom_xml && *rom_xml) ? string(rom_xml) : SnesCartridge(rom_data, rom_size).markup;
|
||||
SNES::cartridge.load(SNES::Cartridge::Mode::Normal, { xmlrom });
|
||||
SNES::system.power();
|
||||
return true;
|
||||
}
|
||||
@ -140,10 +193,10 @@ bool snes_load_cartridge_bsx_slotted(
|
||||
) {
|
||||
snes_cheat_reset();
|
||||
if(rom_data) SNES::cartridge.rom.copy(rom_data, rom_size);
|
||||
string xmlrom = (rom_xml && *rom_xml) ? string(rom_xml) : SNESCartridge(rom_data, rom_size).xmlMemoryMap;
|
||||
string xmlrom = (rom_xml && *rom_xml) ? string(rom_xml) : SnesCartridge(rom_data, rom_size).markup;
|
||||
if(bsx_data) SNES::bsxflash.memory.copy(bsx_data, bsx_size);
|
||||
string xmlbsx = (bsx_xml && *bsx_xml) ? string(bsx_xml) : SNESCartridge(bsx_data, bsx_size).xmlMemoryMap;
|
||||
SNES::cartridge.load(SNES::Cartridge::Mode::BsxSlotted, lstring( xmlrom, xmlbsx ));
|
||||
string xmlbsx = (bsx_xml && *bsx_xml) ? string(bsx_xml) : SnesCartridge(bsx_data, bsx_size).markup;
|
||||
SNES::cartridge.load(SNES::Cartridge::Mode::BsxSlotted, xmlrom);
|
||||
SNES::system.power();
|
||||
return true;
|
||||
}
|
||||
@ -154,10 +207,10 @@ bool snes_load_cartridge_bsx(
|
||||
) {
|
||||
snes_cheat_reset();
|
||||
if(rom_data) SNES::cartridge.rom.copy(rom_data, rom_size);
|
||||
string xmlrom = (rom_xml && *rom_xml) ? string(rom_xml) : SNESCartridge(rom_data, rom_size).xmlMemoryMap;
|
||||
string xmlrom = (rom_xml && *rom_xml) ? string(rom_xml) : SnesCartridge(rom_data, rom_size).markup;
|
||||
if(bsx_data) SNES::bsxflash.memory.copy(bsx_data, bsx_size);
|
||||
string xmlbsx = (bsx_xml && *bsx_xml) ? string(bsx_xml) : SNESCartridge(bsx_data, bsx_size).xmlMemoryMap;
|
||||
SNES::cartridge.load(SNES::Cartridge::Mode::Bsx, lstring( xmlrom, xmlbsx ));
|
||||
string xmlbsx = (bsx_xml && *bsx_xml) ? string(bsx_xml) : SnesCartridge(bsx_data, bsx_size).markup;
|
||||
SNES::cartridge.load(SNES::Cartridge::Mode::Bsx, xmlrom);
|
||||
SNES::system.power();
|
||||
return true;
|
||||
}
|
||||
@ -169,31 +222,32 @@ bool snes_load_cartridge_sufami_turbo(
|
||||
) {
|
||||
snes_cheat_reset();
|
||||
if(rom_data) SNES::cartridge.rom.copy(rom_data, rom_size);
|
||||
string xmlrom = (rom_xml && *rom_xml) ? string(rom_xml) : SNESCartridge(rom_data, rom_size).xmlMemoryMap;
|
||||
string xmlrom = (rom_xml && *rom_xml) ? string(rom_xml) : SnesCartridge(rom_data, rom_size).markup;
|
||||
if(sta_data) SNES::sufamiturbo.slotA.rom.copy(sta_data, sta_size);
|
||||
string xmlsta = (sta_xml && *sta_xml) ? string(sta_xml) : SNESCartridge(sta_data, sta_size).xmlMemoryMap;
|
||||
string xmlsta = (sta_xml && *sta_xml) ? string(sta_xml) : SnesCartridge(sta_data, sta_size).markup;
|
||||
if(stb_data) SNES::sufamiturbo.slotB.rom.copy(stb_data, stb_size);
|
||||
string xmlstb = (stb_xml && *stb_xml) ? string(stb_xml) : SNESCartridge(stb_data, stb_size).xmlMemoryMap;
|
||||
SNES::cartridge.load(SNES::Cartridge::Mode::SufamiTurbo, lstring( xmlrom, xmlsta, xmlstb ));
|
||||
string xmlstb = (stb_xml && *stb_xml) ? string(stb_xml) : SnesCartridge(stb_data, stb_size).markup;
|
||||
SNES::cartridge.load(SNES::Cartridge::Mode::SufamiTurbo, xmlrom);
|
||||
SNES::system.power();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool snes_load_cartridge_super_game_boy(
|
||||
const char *rom_xml, const uint8_t *rom_data, unsigned rom_size,
|
||||
const char *dmg_xml, const uint8_t *dmg_data_, unsigned dmg_size
|
||||
const char *dmg_xml, const uint8_t *dmg_data, unsigned dmg_size
|
||||
) {
|
||||
snes_cheat_reset();
|
||||
if(rom_data) SNES::cartridge.rom.copy(rom_data, rom_size);
|
||||
string xmlrom = (rom_xml && *rom_xml) ? string(rom_xml) : SNESCartridge(rom_data, rom_size).xmlMemoryMap;
|
||||
if(dmg_data_) {
|
||||
uint8_t *dmg_data = new uint8_t[dmg_size]; // GameBoyCartridge might reorder data ...
|
||||
memcpy(dmg_data, dmg_data_, dmg_size);
|
||||
string xmldmg = (dmg_xml && *dmg_xml) ? string(dmg_xml) : GameBoyCartridge(dmg_data, dmg_size).xml;
|
||||
GameBoy::cartridge.load(xmldmg, dmg_data, dmg_size);
|
||||
delete [] dmg_data;
|
||||
string xmlrom = (rom_xml && *rom_xml) ? string(rom_xml) : SnesCartridge(rom_data, rom_size).markup;
|
||||
if(dmg_data) {
|
||||
//GameBoyCartridge needs to modify dmg_data (for MMM01 emulation); so copy data
|
||||
uint8_t *data = new uint8_t[dmg_size];
|
||||
memcpy(data, dmg_data, dmg_size);
|
||||
string xmldmg = (dmg_xml && *dmg_xml) ? string(dmg_xml) : GameBoyCartridge(data, dmg_size).markup;
|
||||
GameBoy::cartridge.load(xmldmg, data, dmg_size);
|
||||
delete[] data;
|
||||
}
|
||||
SNES::cartridge.load(SNES::Cartridge::Mode::SuperGameBoy, lstring( xmlrom, "" ));
|
||||
SNES::cartridge.load(SNES::Cartridge::Mode::SuperGameBoy, xmlrom);
|
||||
SNES::system.power();
|
||||
return true;
|
||||
}
|
||||
@ -203,7 +257,7 @@ void snes_unload_cartridge(void) {
|
||||
}
|
||||
|
||||
bool snes_get_region(void) {
|
||||
return SNES::system.region.i == SNES::System::Region::NTSC ? 0 : 1;
|
||||
return SNES::system.region() == SNES::System::Region::NTSC ? 0 : 1;
|
||||
}
|
||||
|
||||
uint8_t* snes_get_memory_data(unsigned id) {
|
||||
@ -217,20 +271,23 @@ uint8_t* snes_get_memory_data(unsigned id) {
|
||||
if(SNES::cartridge.has_spc7110rtc()) return SNES::spc7110.rtc;
|
||||
return 0;
|
||||
case SNES_MEMORY_BSX_RAM:
|
||||
if(SNES::cartridge.mode.i != SNES::Cartridge::Mode::Bsx) break;
|
||||
if(SNES::cartridge.mode() != SNES::Cartridge::Mode::Bsx) break;
|
||||
return SNES::bsxcartridge.sram.data();
|
||||
case SNES_MEMORY_BSX_PRAM:
|
||||
if(SNES::cartridge.mode.i != SNES::Cartridge::Mode::Bsx) break;
|
||||
if(SNES::cartridge.mode() != SNES::Cartridge::Mode::Bsx) break;
|
||||
return SNES::bsxcartridge.psram.data();
|
||||
case SNES_MEMORY_SUFAMI_TURBO_A_RAM:
|
||||
if(SNES::cartridge.mode.i != SNES::Cartridge::Mode::SufamiTurbo) break;
|
||||
if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SufamiTurbo) break;
|
||||
return SNES::sufamiturbo.slotA.ram.data();
|
||||
case SNES_MEMORY_SUFAMI_TURBO_B_RAM:
|
||||
if(SNES::cartridge.mode.i != SNES::Cartridge::Mode::SufamiTurbo) break;
|
||||
if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SufamiTurbo) break;
|
||||
return SNES::sufamiturbo.slotB.ram.data();
|
||||
case SNES_MEMORY_GAME_BOY_RAM:
|
||||
if(SNES::cartridge.mode.i != SNES::Cartridge::Mode::SuperGameBoy) break;
|
||||
if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SuperGameBoy) break;
|
||||
return GameBoy::cartridge.ramdata;
|
||||
//case SNES_MEMORY_GAME_BOY_RTC:
|
||||
// if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SuperGameBoy) break;
|
||||
// return GameBoy::cartridge.rtcdata;
|
||||
|
||||
case SNES_MEMORY_WRAM:
|
||||
return SNES::cpu.wram;
|
||||
@ -242,9 +299,6 @@ uint8_t* snes_get_memory_data(unsigned id) {
|
||||
return SNES::ppu.oam;
|
||||
case SNES_MEMORY_CGRAM:
|
||||
return SNES::ppu.cgram;
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -262,25 +316,29 @@ unsigned snes_get_memory_size(unsigned id) {
|
||||
if(SNES::cartridge.has_srtc() || SNES::cartridge.has_spc7110rtc()) size = 20;
|
||||
break;
|
||||
case SNES_MEMORY_BSX_RAM:
|
||||
if(SNES::cartridge.mode.i != SNES::Cartridge::Mode::Bsx) break;
|
||||
if(SNES::cartridge.mode() != SNES::Cartridge::Mode::Bsx) break;
|
||||
size = SNES::bsxcartridge.sram.size();
|
||||
break;
|
||||
case SNES_MEMORY_BSX_PRAM:
|
||||
if(SNES::cartridge.mode.i != SNES::Cartridge::Mode::Bsx) break;
|
||||
if(SNES::cartridge.mode() != SNES::Cartridge::Mode::Bsx) break;
|
||||
size = SNES::bsxcartridge.psram.size();
|
||||
break;
|
||||
case SNES_MEMORY_SUFAMI_TURBO_A_RAM:
|
||||
if(SNES::cartridge.mode.i != SNES::Cartridge::Mode::SufamiTurbo) break;
|
||||
if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SufamiTurbo) break;
|
||||
size = SNES::sufamiturbo.slotA.ram.size();
|
||||
break;
|
||||
case SNES_MEMORY_SUFAMI_TURBO_B_RAM:
|
||||
if(SNES::cartridge.mode.i != SNES::Cartridge::Mode::SufamiTurbo) break;
|
||||
if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SufamiTurbo) break;
|
||||
size = SNES::sufamiturbo.slotB.ram.size();
|
||||
break;
|
||||
case SNES_MEMORY_GAME_BOY_RAM:
|
||||
if(SNES::cartridge.mode.i != SNES::Cartridge::Mode::SuperGameBoy) break;
|
||||
if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SuperGameBoy) break;
|
||||
size = GameBoy::cartridge.ramsize;
|
||||
break;
|
||||
//case SNES_MEMORY_GAME_BOY_RTC:
|
||||
// if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SuperGameBoy) break;
|
||||
// size = GameBoy::cartridge.rtcsize;
|
||||
// break;
|
||||
|
||||
case SNES_MEMORY_WRAM:
|
||||
size = 128 * 1024;
|
||||
@ -297,9 +355,6 @@ unsigned snes_get_memory_size(unsigned id) {
|
||||
case SNES_MEMORY_CGRAM:
|
||||
size = 512;
|
||||
break;
|
||||
|
||||
default:
|
||||
size = 0;
|
||||
}
|
||||
|
||||
if(size == -1U) size = 0;
|
||||
|
@ -95,9 +95,9 @@ void PPU::power() {
|
||||
ppu1_version = config.ppu1.version;
|
||||
ppu2_version = config.ppu2.version;
|
||||
|
||||
foreach(n, vram) n = random(0x00);
|
||||
foreach(n, oam) n = random(0x00);
|
||||
foreach(n, cgram) n = random(0x00);
|
||||
for(auto &n : vram) n = random(0x00);
|
||||
for(auto &n : oam) n = random(0x00);
|
||||
for(auto &n : cgram) n = random(0x00);
|
||||
|
||||
reset();
|
||||
}
|
||||
@ -105,7 +105,7 @@ void PPU::power() {
|
||||
void PPU::reset() {
|
||||
create(Enter, system.cpu_frequency);
|
||||
PPUcounter::reset();
|
||||
memset(surface, 0, 512 * 512 * sizeof(uint16));
|
||||
memset(surface, 0, 512 * 512 * sizeof(uint32));
|
||||
|
||||
mmio_reset();
|
||||
bg1.reset();
|
||||
@ -153,7 +153,7 @@ bg4(*this, Background::ID::BG4),
|
||||
sprite(*this),
|
||||
window(*this),
|
||||
screen(*this) {
|
||||
surface = new uint16[512 * 512];
|
||||
surface = new uint32[512 * 512];
|
||||
output = surface + 16 * 512;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
class PPU : public Processor, public PPUcounter {
|
||||
public:
|
||||
struct PPU : public Processor, public PPUcounter {
|
||||
uint8 vram[64 * 1024];
|
||||
uint8 oam[544];
|
||||
uint8 cgram[512];
|
||||
@ -23,8 +22,8 @@ public:
|
||||
~PPU();
|
||||
|
||||
private:
|
||||
uint16 *surface;
|
||||
uint16 *output;
|
||||
uint32 *surface;
|
||||
uint32 *output;
|
||||
|
||||
uint8 ppu1_version;
|
||||
uint8 ppu2_version;
|
||||
|
@ -8,7 +8,7 @@ void PPU::Screen::scanline() {
|
||||
void PPU::Screen::run() {
|
||||
if(ppu.vcounter() == 0) return;
|
||||
|
||||
uint16 color;
|
||||
uint32 color;
|
||||
if(self.regs.pseudo_hires == false && self.regs.bgmode != 5 && self.regs.bgmode != 6) {
|
||||
color = get_pixel(0);
|
||||
*output++ = color;
|
||||
@ -21,7 +21,7 @@ void PPU::Screen::run() {
|
||||
}
|
||||
}
|
||||
|
||||
uint16 PPU::Screen::get_pixel(bool swap) {
|
||||
uint32 PPU::Screen::get_pixel(bool swap) {
|
||||
if(ppu.regs.overscan == false && ppu.vcounter() >= 225) return 0x0000;
|
||||
|
||||
enum source_t { BG1, BG2, BG3, BG4, OAM, BACK };
|
||||
@ -149,9 +149,8 @@ uint16 PPU::Screen::get_pixel(bool swap) {
|
||||
//lighting
|
||||
//========
|
||||
|
||||
output = light_table[self.regs.display_brightness][output];
|
||||
if(self.regs.display_disable) output = 0x0000;
|
||||
return output;
|
||||
if(self.regs.display_disable) return 0;
|
||||
return (self.regs.display_brightness << 15) | output;
|
||||
}
|
||||
|
||||
uint16 PPU::Screen::addsub(unsigned x, unsigned y, bool halve) {
|
||||
@ -206,19 +205,6 @@ void PPU::Screen::reset() {
|
||||
}
|
||||
|
||||
PPU::Screen::Screen(PPU &self) : self(self) {
|
||||
for(unsigned l = 0; l < 16; l++) {
|
||||
for(unsigned r = 0; r < 32; r++) {
|
||||
for(unsigned g = 0; g < 32; g++) {
|
||||
for(unsigned b = 0; b < 32; b++) {
|
||||
double luma = (double)l / 15.0;
|
||||
unsigned ar = static_cast<unsigned>(luma * r + 0.5);
|
||||
unsigned ag = static_cast<unsigned>(luma * g + 0.5);
|
||||
unsigned ab = static_cast<unsigned>(luma * b + 0.5);
|
||||
light_table[l][(r << 10) + (g << 5) + b] = (ab << 10) + (ag << 5) + ar;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,5 +1,5 @@
|
||||
class Screen {
|
||||
uint16 *output;
|
||||
uint32 *output;
|
||||
|
||||
struct Regs {
|
||||
bool addsub_mode;
|
||||
@ -23,8 +23,7 @@ class Screen {
|
||||
void run();
|
||||
void reset();
|
||||
|
||||
uint16 light_table[16][32768];
|
||||
uint16 get_pixel(bool swap);
|
||||
uint32 get_pixel(bool swap);
|
||||
uint16 addsub(unsigned x, unsigned y, bool halve);
|
||||
uint16 get_color(unsigned palette);
|
||||
uint16 get_direct_color(unsigned palette, unsigned tile);
|
||||
|
@ -1,5 +1,4 @@
|
||||
class SMPcore {
|
||||
public:
|
||||
struct SMPcore {
|
||||
#include "registers.hpp"
|
||||
#include "memory.hpp"
|
||||
#include "disassembler/disassembler.hpp"
|
||||
|
@ -71,7 +71,7 @@ void SMP::reset() {
|
||||
regs.sp = 0xef;
|
||||
regs.p = 0x02;
|
||||
|
||||
foreach(n, apuram) n = random(0x00);
|
||||
for(auto &n : apuram) n = random(0x00);
|
||||
apuram[0x00f4] = 0x00;
|
||||
apuram[0x00f5] = 0x00;
|
||||
apuram[0x00f6] = 0x00;
|
||||
|
@ -1,5 +1,4 @@
|
||||
class SMP : public Processor, public SMPcore {
|
||||
public:
|
||||
struct SMP : public Processor, public SMPcore {
|
||||
static const uint8 iplrom[64];
|
||||
uint8 apuram[64 * 1024];
|
||||
|
||||
|
@ -1,35 +1,37 @@
|
||||
#ifndef SNES_HPP
|
||||
#define SNES_HPP
|
||||
|
||||
namespace SNES {
|
||||
namespace Info {
|
||||
static const char Name[] = "bsnes";
|
||||
static const char Version[] = "082";
|
||||
static const unsigned SerializerVersion = 21;
|
||||
static const char Version[] = "083";
|
||||
static const unsigned SerializerVersion = 22;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
bsnes - SNES emulator
|
||||
author: byuu
|
||||
license: GPLv2
|
||||
license: GPLv3
|
||||
project started: 2004-10-14
|
||||
*/
|
||||
|
||||
#include <libco/libco.h>
|
||||
|
||||
//#include <nall/memory_debug.hpp>
|
||||
#include <nall/string.hpp>
|
||||
#include <nall/platform.hpp>
|
||||
#include <nall/algorithm.hpp>
|
||||
#include <nall/array.hpp>
|
||||
#include <nall/detect.hpp>
|
||||
#include <nall/dl.hpp>
|
||||
#include <nall/endian.hpp>
|
||||
#include <nall/file.hpp>
|
||||
#include <nall/foreach.hpp>
|
||||
#include <nall/function.hpp>
|
||||
#include <nall/moduloarray.hpp>
|
||||
#include <nall/platform.hpp>
|
||||
#include <nall/priorityqueue.hpp>
|
||||
#include <nall/property.hpp>
|
||||
#include <nall/serializer.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
#include <nall/string.hpp>
|
||||
#include <nall/utility.hpp>
|
||||
#include <nall/varint.hpp>
|
||||
#include <nall/vector.hpp>
|
||||
@ -148,9 +150,6 @@ namespace SNES {
|
||||
#include <snes/ppu/counter/counter-inline.hpp>
|
||||
}
|
||||
|
||||
namespace nall {
|
||||
template<> struct has_size<SNES::MappedRAM> { enum { value = true }; };
|
||||
template<> struct has_size<SNES::StaticRAM> { enum { value = true }; };
|
||||
}
|
||||
|
||||
#undef debugvirtual
|
||||
|
||||
#endif
|
||||
|
@ -4,16 +4,16 @@ serializer System::serialize() {
|
||||
serializer s(serialize_size);
|
||||
|
||||
unsigned signature = 0x31545342, version = Info::SerializerVersion, crc32 = cartridge.crc32();
|
||||
char profile[16], description[512];
|
||||
memset(&profile, 0, sizeof profile);
|
||||
char description[512], profile[16];
|
||||
memset(&description, 0, sizeof description);
|
||||
memset(&profile, 0, sizeof profile);
|
||||
strlcpy(profile, Info::Profile, sizeof profile);
|
||||
|
||||
s.integer(signature);
|
||||
s.integer(version);
|
||||
s.integer(crc32);
|
||||
s.array(profile);
|
||||
s.array(description);
|
||||
s.array(profile);
|
||||
|
||||
serialize_all(s);
|
||||
return s;
|
||||
@ -21,13 +21,13 @@ serializer System::serialize() {
|
||||
|
||||
bool System::unserialize(serializer &s) {
|
||||
unsigned signature, version, crc32;
|
||||
char profile[16], description[512];
|
||||
char description[512], profile[16];
|
||||
|
||||
s.integer(signature);
|
||||
s.integer(version);
|
||||
s.integer(crc32);
|
||||
s.array(profile);
|
||||
s.array(description);
|
||||
s.array(profile);
|
||||
|
||||
if(signature != 0x31545342) return false;
|
||||
if(version != Info::SerializerVersion) return false;
|
||||
|
@ -63,8 +63,7 @@ void System::runthreadtosave() {
|
||||
}
|
||||
}
|
||||
|
||||
void System::init(Interface *interface_) {
|
||||
interface = interface_;
|
||||
void System::init() {
|
||||
assert(interface != 0);
|
||||
|
||||
icd2.init();
|
||||
@ -241,7 +240,7 @@ void System::scanline() {
|
||||
void System::frame() {
|
||||
}
|
||||
|
||||
System::System() : interface(0) {
|
||||
System::System() {
|
||||
region.i = Region::Autodetect;
|
||||
expansion.i = ExpansionPortDevice::BSX;
|
||||
}
|
||||
|
@ -1,8 +1,6 @@
|
||||
class Interface;
|
||||
struct Interface;
|
||||
|
||||
class System : property<System> {
|
||||
public:
|
||||
Interface *interface;
|
||||
struct System : property<System> {
|
||||
struct Region {
|
||||
enum e {
|
||||
NTSC = 0,
|
||||
@ -21,7 +19,7 @@ public:
|
||||
void run();
|
||||
void runtosave();
|
||||
|
||||
void init(Interface*);
|
||||
void init();
|
||||
void term();
|
||||
void load();
|
||||
void unload();
|
||||
|
@ -21,7 +21,7 @@ const uint8_t Video::cursor[15 * 15] = {
|
||||
};
|
||||
|
||||
void Video::draw_cursor(uint16_t color, int x, int y) {
|
||||
uint16_t *data = (uint16_t*)ppu.output;
|
||||
uint32_t *data = (uint32_t*)ppu.output;
|
||||
if(ppu.interlace() && ppu.field()) data += 512;
|
||||
|
||||
for(int cy = 0; cy < 15; cy++) {
|
||||
@ -34,13 +34,13 @@ void Video::draw_cursor(uint16_t color, int x, int y) {
|
||||
if(vx < 0 || vx >= 256) continue; //do not draw offscreen
|
||||
uint8_t pixel = cursor[cy * 15 + cx];
|
||||
if(pixel == 0) continue;
|
||||
uint16_t pixelcolor = (pixel == 1) ? 0 : color;
|
||||
uint32_t pixelcolor = (15 << 15) | ((pixel == 1) ? 0 : color);
|
||||
|
||||
if(hires == false) {
|
||||
*((uint16_t*)data + vy * 1024 + vx) = pixelcolor;
|
||||
*((uint32_t*)data + vy * 1024 + vx) = pixelcolor;
|
||||
} else {
|
||||
*((uint16_t*)data + vy * 1024 + vx * 2 + 0) = pixelcolor;
|
||||
*((uint16_t*)data + vy * 1024 + vx * 2 + 1) = pixelcolor;
|
||||
*((uint32_t*)data + vy * 1024 + vx * 2 + 0) = pixelcolor;
|
||||
*((uint32_t*)data + vy * 1024 + vx * 2 + 1) = pixelcolor;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -67,21 +67,21 @@ void Video::update() {
|
||||
break;
|
||||
}
|
||||
|
||||
uint16_t *data = (uint16_t*)ppu.output;
|
||||
uint32_t *data = (uint32_t*)ppu.output;
|
||||
if(ppu.interlace() && ppu.field()) data += 512;
|
||||
|
||||
if(hires) {
|
||||
//normalize line widths
|
||||
for(unsigned y = 0; y < 240; y++) {
|
||||
if(line_width[y] == 512) continue;
|
||||
uint16_t *buffer = data + y * 1024;
|
||||
uint32_t *buffer = data + y * 1024;
|
||||
for(signed x = 255; x >= 0; x--) {
|
||||
buffer[(x * 2) + 0] = buffer[(x * 2) + 1] = buffer[x];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
system.interface->video_refresh(ppu.surface, hires, ppu.interlace(), ppu.overscan());
|
||||
interface->videoRefresh(ppu.surface, hires, ppu.interlace(), ppu.overscan());
|
||||
|
||||
hires = false;
|
||||
}
|
||||
@ -97,7 +97,7 @@ void Video::scanline() {
|
||||
|
||||
void Video::init() {
|
||||
hires = false;
|
||||
for(unsigned i = 0; i < 240; i++) line_width[i] = 256;
|
||||
foreach(n, line_width) n = 256;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,4 +1,4 @@
|
||||
class Video {
|
||||
struct Video {
|
||||
private:
|
||||
bool hires;
|
||||
unsigned line_width[240];
|
||||
|
Loading…
x
Reference in New Issue
Block a user