Started merging libsnes port from Themaister.

Does not compile yet, work to do with saves.
Initial emulator not broken.
This commit is contained in:
Philippe Daouadi committed 2011-12-20 18:41:38 +01:00
1 parent b9e485dcad
commit 24fec60c41
12 files changed
+645 -51

No files matched your search

+1
View File
@@ -1 +1,2 @@
Philippe Daouadi <[email protected]>
Hans-Kristian Arntzen (libsnes port and fixes) <[email protected]>
+3 -1
View File
@@ -25,7 +25,9 @@ namespace AMeteor
{
class CartMem
{
public :
public:
virtual ~CartMem() {}
virtual void Reset () = 0;
virtual bool Load (std::istream& stream) = 0;
+4 -48
View File
@@ -14,52 +14,8 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef __GRAPHICS_RENDERER_H__
#define __GRAPHICS_RENDERER_H__
#include <GL/glew.h>
#include <GL/gl.h>
#include <SFML/Graphics/RenderWindow.hpp>
namespace AMeteor
{
namespace Graphics
{
class Renderer : public sf::RenderWindow
{
public:
Renderer(const uint16_t* surface);
~Renderer();
void Init(sf::WindowHandle display = 0);
void Uninit();
void VBlank ();
void EventResize (unsigned int w, unsigned int h);
private :
const uint16_t* m_base;
volatile uint16_t* m_tbase;
volatile unsigned int m_w, m_h;
pthread_t m_thread;
pthread_mutex_t m_mutex;
pthread_cond_t m_cond;
volatile bool m_quit;
GLuint m_pbo;
GLuint m_texture;
GLuint m_vbo;
void InitGl();
void UninitGl();
void StartThread();
void StopThread();
static void* EntryPoint (void* ptr);
void MainLoop ();
};
}
}
#ifdef LIBSNES_BUILD
#include "renderer_libsnes.hpp"
#else
#include "renderer_gl.hpp"
#endif
@@ -0,0 +1,65 @@
// Meteor - A Nintendo Gameboy Advance emulator
// Copyright (C) 2009-2011 Philippe Daouadi
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef __GRAPHICS_RENDERER_GL_H__
#define __GRAPHICS_RENDERER_GL_H__
#include <GL/glew.h>
#include <GL/gl.h>
#include <SFML/Graphics/RenderWindow.hpp>
namespace AMeteor
{
namespace Graphics
{
class Renderer : public sf::RenderWindow
{
public:
Renderer(const uint16_t* surface);
~Renderer();
void Init(sf::WindowHandle display = 0);
void Uninit();
void VBlank ();
void EventResize (unsigned int w, unsigned int h);
private :
const uint16_t* m_base;
volatile uint16_t* m_tbase;
volatile unsigned int m_w, m_h;
pthread_t m_thread;
pthread_mutex_t m_mutex;
pthread_cond_t m_cond;
volatile bool m_quit;
GLuint m_pbo;
GLuint m_texture;
GLuint m_vbo;
void InitGl();
void UninitGl();
void StartThread();
void StopThread();
static void* EntryPoint (void* ptr);
void MainLoop ();
};
}
}
#endif
@@ -0,0 +1,39 @@
// Meteor - A Nintendo Gameboy Advance emulator
// Copyright (C) 2009-2011 Philippe Daouadi
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef __GRAPHICS_RENDERER_LIBSNES_H__
#define __GRAPHICS_RENDERER_LIBSNES_H__
#include <stdint.h>
namespace AMeteor
{
namespace Graphics
{
class Renderer
{
public:
Renderer(const uint16_t* surface);
void VBlank();
private :
const uint16_t* m_base;
};
}
}
#endif
+1 -1
View File
@@ -29,7 +29,7 @@ set(AMeteor_SRC
graphics/bglayer.cpp
graphics/object.cpp
graphics/objects.cpp
graphics/renderer.cpp
graphics/renderer_gl.cpp
graphics/screen.cpp
ameteor.cpp
bios.cpp
@@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "ameteor/graphics/renderer.hpp"
#include "ameteor/graphics/renderer_gl.hpp"
#include "filters/hq4x.hpp"
#include <cstring>
#include <sys/syscall.h>
@@ -0,0 +1,49 @@
// Meteor - A Nintendo Gameboy Advance emulator
// Copyright (C) 2009-2011 Philippe Daouadi
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "ameteor/graphics/renderer.hpp"
#include "ameteor.hpp"
#include "libsnes.hpp"
#include <stdio.h>
extern snes_video_refresh_t psnes_refresh;
namespace AMeteor
{
namespace Graphics
{
Renderer::Renderer (const uint16_t* surface) :
m_base(surface)
{}
void Renderer::VBlank ()
{
uint16_t buf[240 * 160];
for (unsigned i = 0; i < 240 * 160; i++)
{
uint16_t col = m_base[i];
uint16_t b = (col >> 10) & 0x1f;
uint16_t g = (col >> 5) & 0x1f;
uint16_t r = (col >> 0) & 0x1f;
buf[i] = (r << 10) | (g << 5) | (b << 0);
}
// FIXME should not be needed
AMeteor::Stop();
psnes_refresh(buf, 240, 160);
}
}
}
+2
View File
@@ -431,11 +431,13 @@ namespace AMeteor
WRITE(m_memtime);
WRITE(m_memtimeseq);
#undef WRITE
// do we have custom bios
bool b = m_brom;
GZ_WRITE(b);
#define WRITE(var, size) \
if (!gzwrite(file, var, size)) \
return false
// write bios
if (b)
WRITE(m_brom, 0x00004000);
WRITE(m_wbram, 0x00040000);
+107
View File
@@ -0,0 +1,107 @@
ifeq ($(platform),)
platform = unix
ifeq ($(shell uname -a),)
platform = win
else ifneq ($(findstring MINGW,$(shell uname -a)),)
platform = win
else ifneq ($(findstring Darwin,$(shell uname -a)),)
platform = osx
else ifneq ($(findstring win,$(shell uname -a)),)
platform = win
endif
endif
ifeq ($(platform), unix)
TARGET := libsnes.so
fpic := -fPIC
SHARED := -shared -Wl,--version-script=link.T -Wl,--no-undefined
LIBS := -lz
else ifeq ($(platform), osx)
TARGET := libsnes.dylib
fpic := -fPIC
SHARED := -dynamiclib
LIBS := -lz
else
TARGET := snes.dll
CC = gcc
CXX = g++
SHARED := -shared -static-libgcc -static-libstdc++ -s -Wl,--version-script=link.T -Wl,--no-undefined
CFLAGS += -Izlib
CXXFLAGS += -Izlib
endif
CFLAGS += -Wall -pedantic -I. -Iinclude -pipe
CXXFLAGS += -Wall -pedantic -I. -Iinclude -pipe
ifeq ($(DEBUG), 1)
CFLAGS += -O0 -g
CXXFLAGS += -O0 -g
else
CFLAGS += -O3
CXXFLAGS += -O3
endif
SOURCES := libsnes.cpp \
source/audio/dsound.cpp \
source/audio/sound1.cpp \
source/audio/sound2.cpp \
source/audio/sound4.cpp \
source/audio/speaker.cpp \
source/disassembler/argimmediate.cpp \
source/disassembler/argmulregisters.cpp \
source/disassembler/argpsr.cpp \
source/disassembler/argregister.cpp \
source/disassembler/argrelative.cpp \
source/disassembler/argshift.cpp \
source/disassembler/arguimmediate.cpp \
source/disassembler/arguments.cpp \
source/disassembler/instruction.cpp \
source/graphics/bglayer.cpp \
source/graphics/object.cpp \
source/graphics/objects.cpp \
source/graphics/renderer.cpp \
source/graphics/screen.cpp \
source/ameteor.cpp \
source/bios.cpp \
source/clock.cpp \
source/cpu.cpp \
source/debug.cpp \
source/dma.cpp \
source/eeprom.cpp \
source/flash.cpp \
source/cartmem.cpp \
source/interpreter.cpp \
source/interpreter_arm.cpp \
source/interpreter_thumb.cpp \
source/io.cpp \
source/keypad.cpp \
source/lcd.cpp \
source/memory.cpp \
source/sound.cpp \
source/sram.cpp \
source/timer.cpp
ZLIB_SOURCES := $(wildcard zlib/*.c)
ifeq ($(platform), win)
OBJ := $(SOURCES:.cpp=.o) $(ZLIB_SOURCES:.c=.o)
else
OBJ := $(SOURCES:.cpp=.o)
endif
all: $(TARGET)
$(TARGET): $(OBJ)
$(CXX) -o $@ $^ $(SHARED) $(LDFLAGS) $(LIBS)
%.o: %.cpp
$(CXX) -o $@ -c $< $(CXXFLAGS) $(fpic)
%.o: %.c
$(CC) -o $@ -c $< $(CFLAGS) $(fpic)
clean:
rm -f $(TARGET)
rm -f $(OBJ)
.PHONY: clean
+184
View File
@@ -0,0 +1,184 @@
#include "libsnes.hpp"
#include "ameteor.hpp"
#include "ameteor/cartmem.hpp"
#include <stdio.h>
#include <assert.h>
const char* snes_library_id(void) { return "Meteor/libsnes"; }
unsigned snes_library_revision_major(void) { return 1; }
unsigned snes_library_revision_minor(void) { return 3; }
snes_video_refresh_t psnes_refresh;
snes_audio_sample_t psnes_sample;
snes_input_poll_t psnes_poll;
snes_input_state_t psnes_input;
static snes_environment_t psnes_environment;
void snes_set_video_refresh(snes_video_refresh_t video_refresh) { psnes_refresh = video_refresh; }
void snes_set_audio_sample(snes_audio_sample_t audio_sample) { psnes_sample = audio_sample; }
void snes_set_input_poll(snes_input_poll_t input_poll) { psnes_poll = input_poll; }
void snes_set_input_state(snes_input_state_t input_state) { psnes_input = input_state; }
void snes_set_environment(snes_environment_t environment) { psnes_environment = environment; }
void snes_set_controller_port_device(bool, unsigned) {}
void snes_set_cartridge_basename(const char *) {}
void snes_init(void)
{
assert(psnes_environment);
unsigned pitch = 240 * 2;
psnes_environment(SNES_ENVIRONMENT_SET_PITCH, &pitch);
snes_geometry geom = { 240, 160, 240, 160 };
psnes_environment(SNES_ENVIRONMENT_SET_GEOMETRY, &geom);
snes_system_timing timing = { 16777216.0 / 280896.0, 44100.0 };
psnes_environment(SNES_ENVIRONMENT_SET_TIMING, &timing);
AMeteor::CartMem::ClearMemory();
}
void snes_power(void) { AMeteor::Reset(AMeteor::UNIT_ALL ^ AMeteor::UNIT_MEMORY_BIOS); }
void snes_reset(void) { snes_power(); }
void snes_term(void) { snes_power(); }
static bool first_run = true;
void snes_run(void)
{
if (first_run)
{
AMeteor::_memory.LoadCartInferred();
first_run = false;
}
psnes_poll();
AMeteor::Run(10000000);
}
static unsigned serialize_size;
unsigned snes_serialize_size(void)
{
if (first_run)
{
AMeteor::_memory.LoadCartInferred();
first_run = false;
}
AMeteor::omemstream stream(0);
AMeteor::SaveState(stream);
serialize_size = stream.size();
return serialize_size;
}
bool snes_serialize(uint8_t *data, unsigned size)
{
if (!serialize_size)
snes_serialize_size();
if (size != serialize_size)
return false;
AMeteor::omemstream stream(data);
AMeteor::SaveState(stream);
assert(size == stream.size());
return true;
}
bool snes_unserialize(const uint8_t *data, unsigned size)
{
if (!serialize_size)
snes_serialize_size();
if (size != serialize_size)
return false;
AMeteor::imemstream stream(data);
AMeteor::LoadState(stream);
return true;
}
void snes_cheat_reset(void) {}
void snes_cheat_set(unsigned, bool, const char *) {}
bool snes_load_cartridge_normal(
const char *, const uint8_t *data, unsigned size
)
{
if (!AMeteor::_memory.LoadRom(data, size))
return false;
return true;
}
bool snes_load_cartridge_bsx_slotted(
const char *, const uint8_t *, unsigned,
const char *, const uint8_t *, unsigned
)
{
return false;
}
bool snes_load_cartridge_bsx(
const char *, const uint8_t *, unsigned,
const char *, const uint8_t *, unsigned
)
{
return false;
}
bool snes_load_cartridge_sufami_turbo(
const char *, const uint8_t *, unsigned,
const char *, const uint8_t *, unsigned,
const char *, const uint8_t *, unsigned
)
{
return false;
}
bool snes_load_cartridge_super_game_boy(
const char *, const uint8_t *, unsigned,
const char *, const uint8_t *, unsigned
)
{
return false;
}
void snes_unload_cartridge(void) {}
bool snes_get_region(void) { return false; }
uint8_t* snes_get_memory_data(unsigned id)
{
if (id != SNES_MEMORY_CARTRIDGE_RAM)
return 0;
return AMeteor::CartMem::MemoryBuffer();
}
unsigned snes_get_memory_size(unsigned id)
{
if (id != SNES_MEMORY_CARTRIDGE_RAM)
return 0;
switch (AMeteor::_memory.GetCartType())
{
case AMeteor::Memory::CTYPE_UNKNOWN:
case AMeteor::Memory::CTYPE_FLASH128:
return 0x20000;
case AMeteor::Memory::CTYPE_EEPROM512:
return 512;
case AMeteor::Memory::CTYPE_EEPROM8192:
return 8192;
case AMeteor::Memory::CTYPE_FLASH64:
return 0x10000;
case AMeteor::Memory::CTYPE_SRAM:
return 0x8000;
default:
return 0;
}
}
+189
View File
@@ -0,0 +1,189 @@
#ifndef LIBSNES_HPP
#define LIBSNES_HPP
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#define SNES_PORT_1 0
#define SNES_PORT_2 1
#define SNES_DEVICE_NONE 0
#define SNES_DEVICE_JOYPAD 1
#define SNES_DEVICE_MULTITAP 2
#define SNES_DEVICE_MOUSE 3
#define SNES_DEVICE_SUPER_SCOPE 4
#define SNES_DEVICE_JUSTIFIER 5
#define SNES_DEVICE_JUSTIFIERS 6
#define SNES_DEVICE_ID_JOYPAD_B 0
#define SNES_DEVICE_ID_JOYPAD_Y 1
#define SNES_DEVICE_ID_JOYPAD_SELECT 2
#define SNES_DEVICE_ID_JOYPAD_START 3
#define SNES_DEVICE_ID_JOYPAD_UP 4
#define SNES_DEVICE_ID_JOYPAD_DOWN 5
#define SNES_DEVICE_ID_JOYPAD_LEFT 6
#define SNES_DEVICE_ID_JOYPAD_RIGHT 7
#define SNES_DEVICE_ID_JOYPAD_A 8
#define SNES_DEVICE_ID_JOYPAD_X 9
#define SNES_DEVICE_ID_JOYPAD_L 10
#define SNES_DEVICE_ID_JOYPAD_R 11
#define SNES_DEVICE_ID_MOUSE_X 0
#define SNES_DEVICE_ID_MOUSE_Y 1
#define SNES_DEVICE_ID_MOUSE_LEFT 2
#define SNES_DEVICE_ID_MOUSE_RIGHT 3
#define SNES_DEVICE_ID_SUPER_SCOPE_X 0
#define SNES_DEVICE_ID_SUPER_SCOPE_Y 1
#define SNES_DEVICE_ID_SUPER_SCOPE_TRIGGER 2
#define SNES_DEVICE_ID_SUPER_SCOPE_CURSOR 3
#define SNES_DEVICE_ID_SUPER_SCOPE_TURBO 4
#define SNES_DEVICE_ID_SUPER_SCOPE_PAUSE 5
#define SNES_DEVICE_ID_JUSTIFIER_X 0
#define SNES_DEVICE_ID_JUSTIFIER_Y 1
#define SNES_DEVICE_ID_JUSTIFIER_TRIGGER 2
#define SNES_DEVICE_ID_JUSTIFIER_START 3
#define SNES_REGION_NTSC 0
#define SNES_REGION_PAL 1
#define SNES_MEMORY_CARTRIDGE_RAM 0
#define SNES_MEMORY_CARTRIDGE_RTC 1
#define SNES_MEMORY_BSX_RAM 2
#define SNES_MEMORY_BSX_PRAM 3
#define SNES_MEMORY_SUFAMI_TURBO_A_RAM 4
#define SNES_MEMORY_SUFAMI_TURBO_B_RAM 5
#define SNES_MEMORY_GAME_BOY_RAM 6
#define SNES_MEMORY_GAME_BOY_RTC 7
#define SNES_MEMORY_WRAM 100
#define SNES_MEMORY_APURAM 101
#define SNES_MEMORY_VRAM 102
#define SNES_MEMORY_OAM 103
#define SNES_MEMORY_CGRAM 104
// SSNES extension. Not required to be implemented for a working implementation.
#define SNES_ENVIRONMENT_GET_FULLPATH 0 // const char ** --
// Full path of game loaded.
//
#define SNES_ENVIRONMENT_SET_GEOMETRY 1 // const struct snes_geometry * --
// Window geometry information for the system/game.
//
#define SNES_ENVIRONMENT_SET_PITCH 2 // const unsigned * --
// Pitch of game image.
//
#define SNES_ENVIRONMENT_GET_OVERSCAN 3 // bool * --
// Boolean value whether or not the implementation should use overscan.
//
#define SNES_ENVIRONMENT_SET_TIMING 4 // const struct snes_system_timing * --
// Set exact timings of the system. Used primarily for video recording.
//
#define SNES_ENVIRONMENT_GET_CAN_DUPE 5 // bool * --
// Boolean value whether or not SSNES supports frame duping,
// passing NULL to video frame callback.
//
//
#define SNES_ENVIRONMENT_SET_NEED_FULLPATH 6 // const bool * --
// Boolean value telling if implementation needs a valid fullpath to be able to run.
// If this is the case, SSNES will not open the rom directly,
// and pass NULL to rom data.
// Implementation must then use SNES_ENVIRONMENT_GET_FULLPATH.
// This is useful for implementations with very large roms,
// which are impractical to load fully into RAM.
//
#define SNES_ENVIRONMENT_GET_CAN_REWIND 7 // bool * --
// Boolean value telling if SSNES is able to rewind.
// Some implementations might need to take extra precautions
// to allow this as smoothly as possible.
struct snes_geometry
{
unsigned base_width; // Nominal video width of system.
unsigned base_height; // Nominal video height of system.
unsigned max_width; // Maximum possible width of system.
unsigned max_height; // Maximum possible height of system.
};
struct snes_system_timing
{
double fps;
double sample_rate;
};
typedef bool (*snes_environment_t)(unsigned cmd, void *data);
// Must be called before calling snes_init().
void snes_set_environment(snes_environment_t);
////
typedef void (*snes_video_refresh_t)(const uint16_t *data, unsigned width, unsigned height);
typedef void (*snes_audio_sample_t)(uint16_t left, uint16_t right);
typedef void (*snes_input_poll_t)(void);
typedef int16_t (*snes_input_state_t)(bool port, unsigned device, unsigned index, unsigned id);
unsigned snes_library_revision_major(void);
unsigned snes_library_revision_minor(void);
const char *snes_library_id(void);
void snes_set_video_refresh(snes_video_refresh_t);
void snes_set_audio_sample(snes_audio_sample_t);
void snes_set_input_poll(snes_input_poll_t);
void snes_set_input_state(snes_input_state_t);
void snes_set_controller_port_device(bool port, unsigned device);
void snes_set_cartridge_basename(const char *basename);
void snes_init(void);
void snes_term(void);
void snes_power(void);
void snes_reset(void);
void snes_run(void);
unsigned snes_serialize_size(void);
bool snes_serialize(uint8_t *data, unsigned size);
bool snes_unserialize(const uint8_t *data, unsigned size);
void snes_cheat_reset(void);
void snes_cheat_set(unsigned index, bool enabled, const char *code);
bool snes_load_cartridge_normal(
const char *rom_xml, const uint8_t *rom_data, unsigned rom_size
);
bool snes_load_cartridge_bsx_slotted(
const char *rom_xml, const uint8_t *rom_data, unsigned rom_size,
const char *bsx_xml, const uint8_t *bsx_data, unsigned bsx_size
);
bool snes_load_cartridge_bsx(
const char *rom_xml, const uint8_t *rom_data, unsigned rom_size,
const char *bsx_xml, const uint8_t *bsx_data, unsigned bsx_size
);
bool snes_load_cartridge_sufami_turbo(
const char *rom_xml, const uint8_t *rom_data, unsigned rom_size,
const char *sta_xml, const uint8_t *sta_data, unsigned sta_size,
const char *stb_xml, const uint8_t *stb_data, unsigned stb_size
);
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
);
void snes_unload_cartridge(void);
bool snes_get_region(void);
uint8_t* snes_get_memory_data(unsigned id);
unsigned snes_get_memory_size(unsigned id);
#ifdef __cplusplus
}
#endif
#endif