*.bin
InstructionSet_Opcodes.cc
InstructionSet_Tables.cc
-awesomeBoy
+glBoy
test
--- /dev/null
+// Copyright (C) 2011 Michael McMaster <michael@codesrc.com>
+//
+// This file is part of glBoy.
+//
+// glBoy 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.
+//
+// glBoy 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 glBoy. If not, see <http://www.gnu.org/licenses/>.
+
+
+#include "glBoy.hh"
+#include "Core.hh"
+#include "GameboyCart.hh"
+#include "GameboyGraphics.hh"
+#include "GameboyJoypad.hh"
+#include "GameboySound.hh"
+#include "GameboyTimer.hh"
+#include "RAM.hh"
+#include "ROM.hh"
+#include "Log.hh"
+
+#include <SDL/SDL.h>
+#include <SDL/SDL_opengl.h>
+#include <SDL/SDL_video.h>
+
+#include <cassert>
+#include <set>
+#include <sstream>
+
+#include <getopt.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+namespace
+{
+ SDL_Surface*
+ initOpenGL(double xScale, double yScale, bool fullscreen)
+ {
+ glBoy::Log::Instance()(glBoy::Log::DBG_STAT) << "Enabling OpenGL" << std::endl;
+
+ SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+
+ unsigned int options(SDL_OPENGL);
+ if (fullscreen)
+ {
+ options |= SDL_FULLSCREEN;
+ }
+
+ SDL_Surface* surface(
+ SDL_SetVideoMode(160*xScale, 144*yScale, 32, options)
+ );
+
+ glEnable(GL_TEXTURE_2D);
+ glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glDisable(GL_DEPTH_TEST);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0.0f, 160, 144, 0.0f, -1.0f, 1.0f);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ return surface;
+ }
+
+ void usage(const std::string& exe)
+ {
+ std::cout <<
+ "Usage: " << exe << " "
+ "[--scale ratio] [--width w] [--height h] \n"
+ //"\t\t [--resample-method={bilinear|nearest} \n"
+ //"\t\t[--scaling-method={hq4x|scale2x|none}] "
+ "rom.gb" << std::endl <<
+ std::endl <<
+ "\t--scale\t(Default=4.0)" << std::endl <<
+ "\t\tMultiplier applied to the display output dimensions." << std::endl <<
+ "\t--width" << std::endl <<
+ "\t\tSet the display output dimensions directly" << std::endl <<
+ "\t--height" << std::endl <<
+ "\t\tSet the display output dimensions directly" << std::endl;
+ /*"\t--scaling-method\n\t\t\t(Default=\"hq4x\")" << std::endl <<
+ "\t\tSets the upscaling interpolation method." << std::endl <<
+ "\t--resample-method\n\t\t\t(Default=\"bilinear\")" << std::endl <<
+ "\t\tSets the resampling method." << std::endl;*/
+ }
+}
+
+int main(int argc, char** argv)
+{
+ static struct option longOptions[] =
+ {
+ {"video", 1, NULL, 'v'},
+ {"scale", 1, NULL, 's'},
+ {"width", 1, NULL, 'w'},
+ {"height", 1, NULL, 'h'},
+ //{"resample-method", 1, NULL, 'r'},
+ //{"scaling-method", 1, NULL, 'm'},
+ {NULL, 0, NULL, 0}
+ };
+
+ std::string filename("tetris.gb");
+ glBoy::GameboyGraphics::PixelScaler scaler(glBoy::GameboyGraphics::Scaler_hq4x);
+ glBoy::GameboyGraphics::ResampleMethod resampler(glBoy::GameboyGraphics::Resample_Bilinear);
+ bool fullscreen(false);
+ double scaleX(4.0);
+ double scaleY(4.0);
+
+ int optionIndex(0);
+ int c;
+ while (
+ (c = getopt_long(argc, argv, "s:w:h:", &longOptions[0], &optionIndex))
+ != -1)
+ {
+ switch (c)
+ {
+ case 'h':
+ {
+ int height(160);
+ std::stringstream convert(optarg);
+ convert >> height;
+ if (convert && height > 14 && height < 1440)
+ {
+ scaleY = height / 144.0;
+ }
+ }; break;
+ case 'r':
+ {
+ if (std::string(optarg) == "bilinear")
+ {
+ resampler = glBoy::GameboyGraphics::Resample_Bilinear;
+ }
+ else
+ {
+ resampler = glBoy::GameboyGraphics::Resample_Nearest;
+ }
+ }; break;
+ case 's':
+ {
+ double scale(1);
+ std::stringstream convert(optarg);
+ convert >> scale;
+ if (convert && scale > 0.1 && scale < 10)
+ {
+ scaleX = scale;
+ scaleY = scale;
+ }
+ }; break;
+ case 'm':
+ {
+ if (std::string(optarg) == "hq4x")
+ {
+ scaler = glBoy::GameboyGraphics::Scaler_hq4x;
+ }
+ else if (std::string(optarg) == "scale2x")
+ {
+ scaler = glBoy::GameboyGraphics::Scaler_Scale2x;
+ }
+ else
+ {
+ scaler = glBoy::GameboyGraphics::Scaler_None;
+ }
+ }; break;
+ case 'w':
+ {
+ int width(160);
+ std::stringstream convert(optarg);
+ convert >> width;
+ if (convert && width > 16 && width < 1600)
+ {
+ scaleX = width / 160.0;
+ }
+ }; break;
+
+ case '?':
+ usage(argv[0]);
+ exit(1);
+ break;
+
+ default:
+ abort();
+ };
+ }
+
+ if (optind < argc)
+ {
+ filename = argv[optind++];
+ }
+
+ if (access(filename.c_str(), R_OK) != 0)
+ {
+ char* error(strerror(errno));
+ std::cerr << "Could not read file " << filename <<
+ "(" << error << ")" << std::endl;
+ exit(1);
+ }
+
+ glBoy::Core core;
+ glBoy::MemoryMap& map(core.getMemoryMap());
+
+ SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_AUDIO);
+
+ SDL_Surface* surface(initOpenGL(scaleX, scaleY, fullscreen));
+
+ glBoy::GameboyGraphics graphics(core, surface, scaler, resampler);
+
+ // Map the cart memory.
+ int fd(open(filename.c_str(), O_RDONLY));
+ assert(fd >= 0);
+
+ struct stat buf;
+ if (fstat(fd, &buf))
+ {
+ assert(!"Failed fstat");
+ }
+ uint8_t* cart = new uint8_t[buf.st_size];
+ read(fd, cart, buf.st_size);
+ close(fd);
+
+ glBoy::GameboyCart tmp(core, cart, buf.st_size);
+
+
+/*
+ int biosFd(open("DMG_ROM.bin", O_RDONLY));
+ uint8_t bios[256];
+ read(biosFd, bios, 256);
+ std::shared_ptr<glBoy::MemoryMap::Memory> biosMem(new glBoy::ROM(bios, 256));
+ map.map(0, 256, biosMem);
+*/
+
+ // Map the cart mem.
+ // Map the standard internal RAM, plus shadow.
+ {
+ std::shared_ptr<glBoy::MemoryMap::Memory> mem(new glBoy::RAM(8192));
+ map.map(0xC000, 8192, mem);
+ map.map(0xE000, 7680, mem);
+ }
+ // Map the "zero-page" high-speed internal ram.
+ // Most interaction between GB hardware and the program occurs here.
+ {
+ std::shared_ptr<glBoy::MemoryMap::Memory> mem(new glBoy::RAM(128));
+ map.map(0xFF80, 128, mem);
+ }
+
+ // Map the Interrupt flags. Currently handled in Core.cc
+ {
+ std::shared_ptr<glBoy::MemoryMap::Memory> mem(new glBoy::RAM(1));
+ mem->write8(0, 0);
+ map.map(0xFF0F, 1, mem);
+ }
+
+ // Map other devices
+ std::shared_ptr<glBoy::GameboyJoypad> joypad(new glBoy::GameboyJoypad(core));
+ map.map(0xFF00, 1, joypad);
+ std::shared_ptr<glBoy::GameboyTimer> timer(
+ new glBoy::GameboyTimer(
+ core,
+ std::bind(&glBoy::GameboyGraphics::setFrameSkip, &graphics),
+ std::bind(&glBoy::GameboyGraphics::clearFrameSkip, &graphics)
+ )
+ );
+ map.map(0xFF04, 4, timer);
+ std::shared_ptr<glBoy::GameboySound> sound(new glBoy::GameboySound(core));
+ map.map(0xFF10, 48, sound);
+
+ // Cart starts from offset 0x100 with a NOP; JP
+ core.getRegisters().PC = glBoy::htoz(0x100);
+ core.getRegisters().SP = glBoy::htoz(0xFFFE);
+ core.getRegisters().AF = glBoy::htoz(0x01B0);
+ core.getRegisters().BC = glBoy::htoz(0x0013);
+ core.getRegisters().DE = glBoy::htoz(0x00D8);
+ core.getRegisters().HL = glBoy::htoz(0x014D);
+
+ core.run();
+
+ std::cerr << "Done" << std::endl;
+
+ SDL_FreeSurface(surface);
+ SDL_Quit();
+}
+
class MBC1 : public MemoryMap::Memory
{
public:
- MBC1(GameboyCart* parent, uint8_t* begin, uint8_t* end) :
+ MBC1(GameboyCart* parent, const uint8_t* begin, const uint8_t* end) :
m_parent(parent),
m_rom(begin, end),
m_mode(ROM_SELECT),
}
GameboyCart::GameboyCart(
- Core& core, uint8_t* rom, size_t size
+ Core& core, const std::vector<uint8_t>& rom
) :
m_core(core)
{
- if (size < 16384)
+ if (rom.size() < 16384)
{
std::cerr << "Invalid ROM (too small)" << std::endl;
abort();
mbc = "None";
shared_ptr<MemoryMap::Memory> mem(
- new MBC1(this, rom, rom + size)
+ new MBC1(this, &rom[0], &rom[0] + rom.size())
);
/* shared_ptr<MemoryMap::Memory> mem(
new ROM(rom, size)
{
mbc = "MBC1";
shared_ptr<MemoryMap::Memory> mem(
- new MBC1(this, rom, rom + size)
+ new MBC1(this, &rom[0], &rom[0] + rom.size())
);
m_core.getMemoryMap().map(0, 0x8000, mem);
m_romBanks.push_back(mem);
cerr << "Invalid RAM size" << endl;
}
- string title(rom + 0x134, rom + 0x134 + 11);
+ string title(&rom[0x134], &rom[0x134 + 11]);
cout << "Loading Cart" << endl;
cout << "\tTitle:\t\t" << title << endl;
cout << "\tRegion:\t\t" << (rom[0x14A] ? "Worldwide" : "Japan") << endl;
#include "glBoy.hh"
#include "Core.hh"
+#include <vector>
namespace glBoy
{
class GameboyCart
{
public:
- GameboyCart(Core& core, uint8_t* rom, size_t size);
+ GameboyCart(Core& core, const std::vector<uint8_t>& rom);
void setRamBank(size_t bank);
private:
// TODO implement interrupt!
+namespace
+{
+ void setConfiguredKey(
+ const std::map<std::string, int>& keyMap,
+ const libconfig::Config& config,
+ const std::string& configParam,
+ int& mappedKey
+ )
+ {
+ if (config.exists(configParam))
+ {
+ std::string value;
+ config.lookupValue(configParam, value);
+ std::map<std::string, int>::const_iterator it(
+ keyMap.find(value)
+ );
+ if (!value.empty() && it != keyMap.end())
+ {
+ mappedKey = it->second;
+ }
+ }
+ }
+}
-GameboyJoypad::GameboyJoypad(Core& core) :
+GameboyJoypad::GameboyJoypad(Core& core, const libconfig::Config& config) :
m_state(Joypad_Off)
{
+ std::map<std::string, int> sdlKeyMap;
+
+ for (int i = SDLK_FIRST; i < SDLK_LAST; ++i)
+ {
+ std::string keyName = SDL_GetKeyName(static_cast<SDLKey>(i));
+ if (keyName.find("SDLK_") == 0)
+ {
+ keyName = keyName.substr(5);
+ }
+ sdlKeyMap[keyName] = i;
+ }
+
m_inputs[DOWN].sdlKey = SDLK_DOWN;
+ //m_inputs[DOWN].sdlJoystick = 0 or none or something;
m_inputs[UP].sdlKey = SDLK_UP;
m_inputs[LEFT].sdlKey = SDLK_LEFT;
m_inputs[RIGHT].sdlKey = SDLK_RIGHT;
m_inputs[A].sdlKey = SDLK_a;
m_inputs[B].sdlKey = SDLK_s;
+ setConfiguredKey(sdlKeyMap, config, "glBoy.keys.up", m_inputs[UP].sdlKey);
+ setConfiguredKey(sdlKeyMap, config, "glBoy.keys.down", m_inputs[DOWN].sdlKey);
+ setConfiguredKey(sdlKeyMap, config, "glBoy.keys.left", m_inputs[LEFT].sdlKey);
+ setConfiguredKey(sdlKeyMap, config, "glBoy.keys.right", m_inputs[RIGHT].sdlKey);
+ setConfiguredKey(sdlKeyMap, config, "glBoy.keys.start", m_inputs[START].sdlKey);
+ setConfiguredKey(sdlKeyMap, config, "glBoy.keys.select", m_inputs[SELECT].sdlKey);
+ setConfiguredKey(sdlKeyMap, config, "glBoy.keys.a", m_inputs[A].sdlKey);
+ setConfiguredKey(sdlKeyMap, config, "glBoy.keys.b", m_inputs[B].sdlKey);
+
pollInput(0);
using namespace std::placeholders;
case SDL_KEYUP:
case SDL_KEYDOWN:
{
+ if (event.key.keysym.sym == SDLK_ESCAPE)
+ {
+ exit(0);
+ }
+
for (int i = 0; i < 8; ++i)
{
if (event.key.keysym.sym == m_inputs[i].sdlKey)
#include "MemoryMap.hh"
+#include <libconfig.h++>
#include <SDL/SDL.h>
namespace glBoy
class GameboyJoypad : public MemoryMap::Memory
{
public:
- GameboyJoypad(Core& core);
+ GameboyJoypad(Core& core, const libconfig::Config& config);
void pollInput(Core::CallbackId id);
{
Input() : sdlKey(0), depressed(false) {}
int sdlKey;
+ int sdlJoystick;
bool depressed;
};
// You should have received a copy of the GNU General Public License
// along with glBoy. If not, see <http://www.gnu.org/licenses/>.
-
+#define GLX_GLXEXT_PROTOTYPES 1
#include "glBoy.hh"
#include "Core.hh"
#include "GameboyCart.hh"
#include "ROM.hh"
#include "Log.hh"
+#include <GL/glext.h>
#include <SDL/SDL.h>
#include <SDL/SDL_opengl.h>
#include <SDL/SDL_video.h>
+#include <libconfig.h++>
+#include <zipios++/zipfile.h>
+
#include <cassert>
#include <set>
#include <sstream>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
+#include <pwd.h>
namespace
{
+ enum Constants
+ {
+ GLBOY_MIN_WIDTH = 16,
+ GLBOY_MAX_WIDTH = 1600,
+
+ GLBOY_MIN_HEIGHT = 14,
+ GLBOY_MAX_HEIGHT = 1440,
+ };
+
SDL_Surface*
initOpenGL(double xScale, double yScale, bool fullscreen)
{
SDL_SetVideoMode(160*xScale, 144*yScale, 32, options)
);
+ // v-sync
+ //::glXSwapIntervalSGI(1);
+
glEnable(GL_TEXTURE_2D);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
"\t--resample-method\n\t\t\t(Default=\"bilinear\")" << std::endl <<
"\t\tSets the resampling method." << std::endl;*/
}
+
+ void readConfigFile(libconfig::Config& config)
+ {
+ // Grab the current user's home dir
+ struct passwd* entry(getpwuid(getuid()));
+ if (entry && entry->pw_dir)
+ {
+ std::stringstream file;
+ file << entry->pw_dir << "/" << ".glBoy";
+ try
+ {
+ config.readFile(file.str().c_str());
+ }
+ catch (libconfig::FileIOException& e)
+ {
+ // Ignore. config file probably doesn't exist.
+ }
+ catch (libconfig::ParseException& e)
+ {
+ std::cerr << "Error while parsing file " <<
+ file.str() << std::endl <<
+ e.getError() << " at line " << e.getLine() <<
+ std::endl;
+
+ // Continue with default options.
+ }
+ catch (libconfig::ConfigException& e)
+ {
+ std::cerr << "Error while reading config file " <<
+ file.str() << " : " << std::endl;
+
+ // Continue with default options.
+ }
+ }
+ }
+
+ std::vector<uint8_t> readCart(const std::string& filename)
+ {
+ std::vector<uint8_t> result;
+
+ // Map the cart memory.
+ int fd(open(filename.c_str(), O_RDONLY));
+ if (fd <= 0)
+ {
+ char* err(strerror(errno));
+ std::cerr << "Failed to load file " << filename << std::endl <<
+ err << std::endl;
+ exit(1);
+ }
+
+ struct stat buf;
+ if (fstat(fd, &buf))
+ {
+ assert(!"Failed fstat");
+ }
+
+ if (buf.st_size > 1024*1024)
+ {
+ // Probably not a rom at all.
+ std::cerr << "Cart too large" << std::endl;
+ exit(1);
+ }
+
+ char zipHeader[2] = {'\0', '\0'};
+ read(fd, zipHeader, sizeof(zipHeader));
+ lseek(fd, 0, SEEK_SET);
+
+ if (zipHeader[0] == 'P' && zipHeader[1] == 'K')
+ {
+ // Unzip
+ using namespace zipios;
+ try
+ {
+ ZipFile zf(filename);
+ ConstEntries entries(zf.entries());
+ if (!entries.empty())
+ {
+ glBoy::Log::Instance()(glBoy::Log::DBG_STAT) <<
+ "Uncompressing " << entries.front()->getName() << std::endl;
+ std::auto_ptr<std::istream> is(
+ zf.getInputStream(entries.front())
+ );
+std::cerr << "*" << std::endl;
+ result.resize(entries.front()->getSize());
+std::cerr << "*" << std::endl;
+ is->rdbuf()->sgetn(
+ reinterpret_cast<char*>(&result[0]),
+ result.size()
+ );
+std::cerr << "*" << std::endl;
+ }
+ } catch (std::exception& e)
+ {
+ std::cerr << "Error while reading file " << filename <<
+ std::endl <<
+ e.what() << std::endl;
+ }
+ }
+ else
+ {
+ result.resize(buf.st_size);
+ read(fd, &result[0], result.size());
+ }
+ close(fd);
+
+ return result;
+ }
+
}
int main(int argc, char** argv)
{
+ std::cout << PACKAGE_STRING << " <" << PACKAGE_BUGREPORT << ">" << std::endl;
+ libconfig::Config config;
+ config.setAutoConvert(true); // Allow conversions between int/float
+ readConfigFile(config);
+
static struct option longOptions[] =
{
{"video", 1, NULL, 'v'},
};
std::string filename("tetris.gb");
+ config.lookupValue("glBoy.rom", filename);
+
glBoy::GameboyGraphics::PixelScaler scaler(glBoy::GameboyGraphics::Scaler_hq4x);
glBoy::GameboyGraphics::ResampleMethod resampler(glBoy::GameboyGraphics::Resample_Bilinear);
bool fullscreen(false);
double scaleX(4.0);
double scaleY(4.0);
+ if (config.exists("glBoy.screen.width"))
+ {
+ int width(0);
+ config.lookupValue("glBoy.screen.width", width);
+ if (width >= GLBOY_MIN_WIDTH && width <= GLBOY_MAX_WIDTH)
+ {
+ scaleX = width / 160.0;
+ }
+ }
+ if (config.exists("glBoy.screen.height"))
+ {
+ int height(0);
+ config.lookupValue("glBoy.screen.height", height);
+ if (height >= GLBOY_MIN_HEIGHT && height <= GLBOY_MAX_HEIGHT)
+ {
+ scaleY = height / 144.0;
+ }
+ }
+
int optionIndex(0);
int c;
while (
int height(160);
std::stringstream convert(optarg);
convert >> height;
- if (convert && height > 14 && height < 1440)
+ if (convert &&
+ height >= GLBOY_MIN_HEIGHT && height <= GLBOY_MAX_HEIGHT
+ )
{
scaleY = height / 144.0;
}
int width(160);
std::stringstream convert(optarg);
convert >> width;
- if (convert && width > 16 && width < 1600)
+ if (convert &&
+ width >= GLBOY_MIN_WIDTH && width <= GLBOY_MAX_WIDTH
+ )
{
scaleX = width / 160.0;
}
filename = argv[optind++];
}
+ if (access(filename.c_str(), R_OK) != 0)
+ {
+ char* error(strerror(errno));
+ std::cerr << "Could not read file " << filename <<
+ " (" << error << ")" << std::endl;
+ exit(1);
+ }
+
glBoy::Core core;
glBoy::MemoryMap& map(core.getMemoryMap());
glBoy::GameboyGraphics graphics(core, surface, scaler, resampler);
- // Map the cart memory.
- int fd(open(filename.c_str(), O_RDONLY));
- assert(fd >= 0);
+ SDL_WM_SetCaption("glBoy", "glBoy");
+ // TODO SDL_WM_SetIcon
- struct stat buf;
- if (fstat(fd, &buf))
- {
- assert(!"Failed fstat");
- }
- uint8_t* cart = new uint8_t[buf.st_size];
- read(fd, cart, buf.st_size);
- close(fd);
+ std::vector<uint8_t> cart(readCart(filename));
+ glBoy::GameboyCart tmp(core, cart);
- glBoy::GameboyCart tmp(core, cart, buf.st_size);
-
-
-/*
- int biosFd(open("DMG_ROM.bin", O_RDONLY));
- uint8_t bios[256];
- read(biosFd, bios, 256);
- std::shared_ptr<glBoy::MemoryMap::Memory> biosMem(new glBoy::ROM(bios, 256));
- map.map(0, 256, biosMem);
-*/
// Map the cart mem.
// Map the standard internal RAM, plus shadow.
}
// Map other devices
- std::shared_ptr<glBoy::GameboyJoypad> joypad(new glBoy::GameboyJoypad(core));
+ std::shared_ptr<glBoy::GameboyJoypad> joypad(
+ new glBoy::GameboyJoypad(core, config)
+ );
map.map(0xFF00, 1, joypad);
std::shared_ptr<glBoy::GameboyTimer> timer(
new glBoy::GameboyTimer(
+++ /dev/null
-# Copyright (C) 2011 Michael McMaster <michael@codesrc.com>
-#
-# This file is part of glBoy.
-#
-# glBoy 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.
-#
-# glBoy 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 glBoy. If not, see <http://www.gnu.org/licenses/>.
-
-VERSION=$(shell cat VERSION)
-
-all: glBoy
-
-OBJS = \
- ALU.o \
- Core.o \
- GameboyCart.o \
- GameboyGraphics.o \
- GameboyJoypad.o \
- GameboySound.o \
- GameboyTimer.o \
- hq4x.o \
- Log.o \
- Main.o \
- MemoryMap.o \
- RAM.o \
- Registers.o \
- ROM.o \
-
-DEFINES=
-# -DGLBOY_DEBUG
-
-CPPFLAGS=-DHOST_LITTLE_ENDIAN -I. $(DEFINES)
-CXXFLAGS=-g -O3 -march=native -W -Wall -Werror -std=c++0x
-
-LDFLAGS=-lSDL -lGL -lGLU -lglut
-
-glBoy: InstructionSet_Opcodes.cc $(OBJS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ $(OBJS)
-
-InstructionSet_Opcodes.cc: InstructionSet.opcode makeOpcodes.pl
- perl ./makeOpcodes.pl
-
-Core.o: InstructionSet_Opcodes.cc
-
-test: InstructionSet_Opcodes.cc Test.cc ALU.cc
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $@ Test.cc ALU.cc
-
-package:
- git commit -a
- git tag -a -f $(VERSION)
- -mkdir /tmp/glBoy-$(VERSION)
- -rm /tmp/glBoy-$(VERSION)/*
- cp *.cc *.hh *.opcode *.pl Makefile COPYING README VERSION /tmp/glBoy-$(VERSION)/
- tar cvf glBoy-$(VERSION).tar -C /tmp glBoy-$(VERSION)
- gzip glBoy-$(VERSION).tar
-
-clean:
- -rm -f *.o
- -rm -f glBoy
- -rm -f InstructionSet_Opcodes.cc
- -rm -f InstructionSet_Tables.cc
- -rm -f gmon.out
--- /dev/null
+# Copyright (C) 2011 Michael McMaster <michael@codesrc.com>
+#
+# This file is part of glBoy.
+#
+# glBoy 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.
+#
+# glBoy 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 glBoy. If not, see <http://www.gnu.org/licenses/>.
+
+check_PROGRAMS = \
+ test_alu
+
+TESTS = $(check_PROGRAMS)
+
+test_alu_SOURCES = Test.cc ALU.cc
+
+dist_noinst_SCRIPTS = autogen.sh
+
+EXTRA_DIST = \
+ configure.ac \
+ glBoy.config \
+ InstructionSet.opcode \
+ Makefile.am \
+ COPYING \
+ NEWS \
+ README \
+ VERSION
+
+bin_PROGRAMS = glBoy
+
+glBoy_SOURCES = \
+ ALU.hh \
+ ALU.cc \
+ Core.hh \
+ Core.cc \
+ DAA.hh \
+ DWORD.hh \
+ GameboyCart \
+ GameboyCart.cc \
+ GameboyGraphics.hh \
+ GameboyGraphics.cc \
+ GameboyJoypad.hh \
+ GameboyJoypad.cc \
+ GameboySound.hh \
+ GameboySound.cc \
+ GameboyTimer.hh \
+ GameboyTimer.cc \
+ glBoy.hh \
+ hq4x.hh \
+ hq4x.cc \
+ Log.hh \
+ Log.cc \
+ Main.cc \
+ MemoryMap.hh \
+ MemoryMap.cc \
+ RAM.hh \
+ RAM.cc \
+ Registers.hh \
+ Registers.cc \
+ ROM.hh \
+ ROM.cc \
+ util.hh
+
+BUILT_SOURCES = \
+ InstructionSet_Opcodes.cc
+
+nodist_glBoy_SOURCES =
+ InstructionSet_Opcodes.cc
+
+CLEANFILES = \
+ InstructionSet_Opcodes.cc \
+ InstructionSet_Tables.cc
+
+glBoy_LDFLAGS = -lGL -lGLU -lzipios
+
+CXXFLAGS=-g -O3 -march=native -W -Wall -Werror -std=c++0x
+
+InstructionSet_Opcodes.cc: InstructionSet.opcode makeOpcodes.pl
+ perl $(srcdir)/makeOpcodes.pl $<
+
+#package: clean
+# git commit -a
+# git tag -a -f $(VERSION)
+
}\r
\r
\r
-const MemoryMap::MappedArea&\r
+inline const MemoryMap::MappedArea&\r
MemoryMap::get(uint16_t address) const\r
{\r
\r
}\r
}\r
\r
+ return getFailed(address);\r
+}\r
+\r
+const MemoryMap::MappedArea&\r
+MemoryMap::getFailed(uint16_t address) const\r
+{\r
Log::Instance()(Log::DBG_MEMORY) <<\r
"Returning NULL memory for address " << glBoy::hex(address) << std::endl;\r
\r
\r
bool operator<(const MappedArea& b) const { return base < b.base; }\r
};\r
- const MappedArea& get(uint16_t address) const;\r
+ inline const MappedArea& get(uint16_t address) const;\r
+ const MappedArea& getFailed(uint16_t address) const;\r
\r
typedef std::vector<MappedArea> MapType;\r
MapType m_map;\r
--- /dev/null
+2011-FIXME Version 1.0.1
+ - Increased performance for some NVidia Quadro cards (tested with NVS 290)
+ - Added configurable key mappings. Copy glBoy.config to ~/.glBoy to change
+ settings.
+
+2011-01-31 Version 1.0.0
+ - Initial release
+
glBoy
-Original gameboy emulator.
+Original gameboy emulator by Michael McMaster <michael@codesrc.com>
Usage:
Usage: ./glBoy [--scale ratio] [--width w] [--height h] rom.gb
--- /dev/null
+// Copyright (C) 2011 Michael McMaster <michael@codesrc.com>
+//
+// This file is part of glBoy.
+//
+// glBoy 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.
+//
+// glBoy 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 glBoy. If not, see <http://www.gnu.org/licenses/>.
+
+#include "glBoy.hh"
+
+// Simple Unzip implementation
+// Limitations:
+// - Does not support spanned archives.
+// - Does not support spanned encryption.
+// - Does not support zip64
+
+
+uint32_t
+read32(const std::vector<uint8_t>& zipData, size_t pos)
+{
+ // Read 4 bytes in little-endian order.
+ // Return results in host-endian.
+ return uint32_t(
+ zipData[pos] |
+ (static_cast<uint32_t>(zipData[pos+1]) << 8) |
+ (static_cast<uint32_t>(zipData[pos+2]) << 16) |
+ (static_cast<uint32_t>(zipData[pos+3]) << 24)
+ );
+}
+
+uint16_t
+read16(const std::vector<uint8_t>& zipData, size_t pos)
+{
+ // Read 2 bytes in little-endian order.
+ // Return results in host-endian.
+ return uint16_t(
+ zipData[pos] |
+ (static_cast<uint16_t>(zipData[pos+1]) << 8) |
+ );
+}
+
+struct EndCentralDir
+{
+ size_t centralDirectoryBytes;
+ size_t centralDirectoryOffset;
+ size_t centralDirectoryEntries;
+ std::string zipFileComment;
+};
+
+TODO lets make this somewhat full-featured.
+Accept a CLASS as input, with a readZipBytes virtual method.
+And accept a different class with a writeUncompressedBytes method when
+uncompressing.
+EndCentralDir readEndRecord(const std::vector<uint8_t>& zipData)
+{
+ // Read the end of central directory record. This
+ // record enables us to find the remainding
+ // records without searching for record signatures.
+
+ enum
+ {
+ MinRecordBytes = 22, // Minimum size with no comment
+ MaxCommentBytes = 65535, // 2 bytes to store comment length
+ Signature = 0x06054b50
+ };
+
+ if (zipData.size() < MinRecordBytes)
+ {
+ throw ZipFormatException("Too small");
+ }
+
+ // Need to search for this record, as it ends in a variable-length
+ // comment field. Search backwards, with the assumption that the
+ // comment doesn't exist, or is much smaller than the maximum
+ // length
+ size_t end(0);
+ if (zipData.size() > MinRecordBytes + MaxCommentBytes)
+ {
+ end = zipData.size() - MinRecordBytes + MaxCommentBytes;
+ }
+ size_t start(zipData.size() - MinRecordBytes);
+
+ bool recordFound(false);
+ size_t pos(start);
+ for (; pos >= end; --pos)
+ {
+ recordFound = (read32(zipData, pos) == Signature);
+ break;
+ }
+
+ if (!recordFound)
+ {
+ throw ZipFormatException("ZIP directory records not found");
+ }
+
+ if (read16(zipData, pos + 4) != 1)
+ {
+ throw ZipUnsupportedException("Spanned disks not supported");
+ }
+
+ EndCentralDir result;
+ result.entralDirectoryBytes = read32(zipData, pos + 12);
+ result.centralDirectoryOffset = read32(zipData, pos + 16);
+ result.centralDirectoryEntries = read16(zipData, pos + 10);
+
+ size_t commentLength(read16(zipData, pos + 20));
+ size_t commentStart(pos + MinRecordBytes);
+ if (commentStart + commentLength > zipData.size())
+ {
+ throw ZipFormatException("ZIP comment is too long");
+ }
+ result.zipFileComment =
+ std::string(
+ &zipData[commentStart],
+ &zipData[commentStart + commentLength]
+ );
+
+ return result;
+}
+
--- /dev/null
+#!/bin/sh
+autoreconf --force --install
--- /dev/null
+AC_INIT([glBoy], [1.0.1], [michael@codesrc.com])
+AC_CANONICAL_HOST
+AC_CANONICAL_TARGET
+AM_INIT_AUTOMAKE([foreign])
+AC_CONFIG_HEADERS([autoconfig.h])
+AC_CONFIG_FILES([Makefile])
+
+AC_C_BIGENDIAN(
+ AC_DEFINE([HOST_BIG_ENDIAN], [], [Compile for big-endian host cpu]),
+ AC_DEFINE([HOST_LITTLE_ENDIAN], [], [Compile for litte-endian host cpu])
+ )
+
+AC_PROG_CXX
+
+SDL_VERSION=1.2.0
+AM_PATH_SDL(
+ $SDL_VERSION,
+ :,
+ AC_MSG_ERROR([*** SDL version $SDL_VERSION not found!])
+ )
+CFLAGS="$CFLAGS $SDL_CFLAGS" LIBS="$LIBS $SDL_LIBS"
+
+#AC_ARG_ENABLE([GLBOY_DEBUG],
+# AS_HELP_STRING([--enable-debug_trace],
+# [Enable debug trace logging]),
+# [AC_DEFINE(GLBOY_DEBUG),
+#FIXME
+# [])
+
+PKG_CHECK_MODULES([LIBCONFIGXX], [libconfig++ >= 1.3],,
+ AC_MSG_ERROR([libconfig++ 1.3 or newer not found.])
+)
+CFLAGS="$CFLAGS $LIBCONFIGXX_CFLAGS" LIBS="$LIBS $LIBCONFIGXX_LIBS"
+
+#AX_CXXFLAGS_GCC_OPTION([-std=c++0x])
+#- warning flags
+#- opt flags ?
+#- debug flags ?
+#GL lib, GLU lib
+#flto!
+
+AC_OUTPUT
+
--- /dev/null
+# glBoy example configuration file
+
+TODO list available keys here in a comment.
+change name to ~/.glBoy/config as we need a directory for saved games as well.
+
+glBoy:
+{
+ keys:
+ {
+ up = "UP";
+ down = "DOWN";
+ left = "LEFT";
+ right = "RIGHT";
+ start = "RETURN";
+ select = "BACKSPACE";
+ a = "z";
+ b = "x";
+ };
+
+ screen:
+ {
+ width = 160;
+ height = 144;
+ };
+
+ rom = "tetris.gb";
+};
#ifndef GLBOY_HH\r
#define GLBOY_HH\r
\r
+#include "autoconfig.h"\r
+\r
#include <cstdint>\r
#include <iostream>\r
\r
"\\r
// Enable bitwise operators\n\\r
#version 130\n\\r
+\n\\r
+#ifdef __GLSL_CG_DATA_TYPES\n\\r
+// NVidia specific\n\\r
+// These pragmas make a MASSIVE difference on some quadro cards.\n\\r
+// But no difference on my 6600.\n\\r
+#pragma optionNV(fastmath on)\n\\r
+#pragma optionNV(fastprecision on)\n\\r
+#pragma optionNV(ifcvt none)\n\\r
+#pragma optionNV(inline all)\n\\r
+#pragma optionNV(strict on)\n\\r
+#pragma optionNV(unroll all)\n\\r
+#endif\n\\r
+\n\\r
\\r
uniform sampler2D mmTexture;\n\\r
uniform sampler2D mmLookup;\n\\r
# </ Ugly Globals >
-my $reader = new XML::LibXML::Reader(location => "InstructionSet.opcode")
+my $reader = new XML::LibXML::Reader(location => $ARGV[0])
|| die "Cannot read opcode file\n";
open (TABLES, '>InstructionSet_Tables.cc') || die "Could not write to file\n";