Compare commits

...
Sign in to create a new pull request.

1 commit

Author SHA1 Message Date
Ilari Liusvaara
563a2f2956 Support meteor core for GBA 2014-04-18 21:56:00 +03:00
9 changed files with 1098 additions and 16 deletions

1
.gitignore vendored
View file

@ -13,5 +13,6 @@ lsnes
/core
/bsnes
/gambatte
/meteor
src/fonts/font.cpp
src/core/version.cpp

View file

@ -99,7 +99,21 @@ SVN r320, r358 or r364
\end_layout
\begin_layout Enumerate
Patched with included patches
Patched with included patch.
\end_layout
\end_deeper
\begin_layout Enumerate
meteor (for meteor core)
\end_layout
\begin_deeper
\begin_layout Enumerate
1.4.0
\end_layout
\begin_layout Enumerate
Patched with included patch.
\end_layout
\end_deeper

View file

@ -16,33 +16,39 @@ lsnes is SNES rerecording emulator based on bsnes core.
(a) SVN r320, r358 or r364
(b) Patched with included patches
(b) Patched with included patch.
3. Zlib
3. meteor (for meteor core)
4. boost_iostreams
(a) 1.4.0
5. boost_filesystem
(b) Patched with included patch.
6. boost_thread (if native std::thread is not available)
4. Zlib
7. libsdl (SDL only)
5. boost_iostreams
8. sdlmain (SDL only, part of SDL)
6. boost_filesystem
9. boost_conversion (this is header-only library)
7. boost_thread (if native std::thread is not available)
10. libswscale (wxwidgets graphics only)
8. libsdl (SDL only)
11. Portaudio (portaudio sound only)
9. sdlmain (SDL only, part of SDL)
12. libao (libao sound only)
10. boost_conversion (this is header-only library)
13. Lua version 5.1.X or 5.2.X
11. libswscale (wxwidgets graphics only)
14. G++ 4.6 or 4.7
12. Portaudio (portaudio sound only)
15. libopus (optional, for commentary track tool)
13. libao (libao sound only)
14. Lua version 5.1.X or 5.2.X
15. G++ 4.6 or 4.7
16. libopus (optional, for commentary track tool)
3 Building

View file

@ -0,0 +1,489 @@
From c3059a59fa95cd0e165dbcf7df4b9dc11d5b8d29 Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Sun, 17 Feb 2013 11:18:50 +0200
Subject: [PATCH] Add memory watch features
---
Makefile | 60 ++++++++++++++++++
ameteor/include/ameteor/cartmem.hpp | 2 +
ameteor/include/ameteor/graphics/bglayer.hpp | 3 +
ameteor/include/ameteor/io.hpp | 3 +
ameteor/include/ameteor/memory.hpp | 2 +
ameteor/source/clock.cpp | 3 +-
ameteor/source/graphics/bglayer.cpp | 85 ++++++++++++++------------
ameteor/source/graphics/screen.cpp | 22 +++++++
ameteor/source/io.cpp | 15 ++++-
ameteor/source/memory.cpp | 33 +++++++++--
10 files changed, 180 insertions(+), 48 deletions(-)
create mode 100644 Makefile
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..463a2f7
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,60 @@
+TARGET=libmeteor.$(ARCHIVE_SUFFIX)
+CXXFLAGS += -Wall -Wno-parentheses -I. -Iameteor/include -D__LIBRETRO__ -O3 -g
+
+SRCDIR := ameteor/source
+
+SOURCES := \
+ $(SRCDIR)/audio/dsound.cpp \
+ $(SRCDIR)/audio/sound1.cpp \
+ $(SRCDIR)/audio/sound2.cpp \
+ $(SRCDIR)/audio/sound4.cpp \
+ $(SRCDIR)/audio/speaker.cpp \
+ $(SRCDIR)/disassembler/argimmediate.cpp \
+ $(SRCDIR)/disassembler/argmulregisters.cpp \
+ $(SRCDIR)/disassembler/argpsr.cpp \
+ $(SRCDIR)/disassembler/argregister.cpp \
+ $(SRCDIR)/disassembler/argrelative.cpp \
+ $(SRCDIR)/disassembler/argshift.cpp \
+ $(SRCDIR)/disassembler/arguimmediate.cpp \
+ $(SRCDIR)/disassembler/arguments.cpp \
+ $(SRCDIR)/disassembler/instruction.cpp \
+ $(SRCDIR)/graphics/bglayer.cpp \
+ $(SRCDIR)/graphics/object.cpp \
+ $(SRCDIR)/graphics/objects.cpp \
+ $(SRCDIR)/graphics/renderer.cpp \
+ $(SRCDIR)/graphics/screen.cpp \
+ $(SRCDIR)/ameteor.cpp \
+ $(SRCDIR)/bios.cpp \
+ $(SRCDIR)/clock.cpp \
+ $(SRCDIR)/cpu.cpp \
+ $(SRCDIR)/debug.cpp \
+ $(SRCDIR)/dma.cpp \
+ $(SRCDIR)/eeprom.cpp \
+ $(SRCDIR)/flash.cpp \
+ $(SRCDIR)/cartmem.cpp \
+ $(SRCDIR)/interpreter.cpp \
+ $(SRCDIR)/interpreter_arm.cpp \
+ $(SRCDIR)/interpreter_thumb.cpp \
+ $(SRCDIR)/io.cpp \
+ $(SRCDIR)/keypad.cpp \
+ $(SRCDIR)/lcd.cpp \
+ $(SRCDIR)/memory.cpp \
+ $(SRCDIR)/sound.cpp \
+ $(SRCDIR)/sram.cpp \
+ $(SRCDIR)/timer.cpp
+
+OBJ := $(SOURCES:.cpp=.$(OBJECT_SUFFIX))
+
+all: $(TARGET)
+
+$(TARGET): $(OBJ)
+ $(REALAR) crvs $@ $^
+
+%.$(OBJECT_SUFFIX): %.cpp
+ $(CXX) -o $@ -c $< $(CXXFLAGS)
+
+clean:
+ rm -f $(TARGET)
+ rm -f $(OBJ)
+
+.PHONY: clean
diff --git a/ameteor/include/ameteor/cartmem.hpp b/ameteor/include/ameteor/cartmem.hpp
index e7ee436..a18e6d6 100644
--- a/ameteor/include/ameteor/cartmem.hpp
+++ b/ameteor/include/ameteor/cartmem.hpp
@@ -44,6 +44,8 @@ namespace AMeteor
virtual bool SaveState (std::ostream& stream);
virtual bool LoadState (std::istream& stream);
+ uint8_t* GetRawData() { return m_data; }
+ uint32_t GetRawSize() { return m_size; }
protected:
uint8_t* m_data;
uint32_t m_size;
diff --git a/ameteor/include/ameteor/graphics/bglayer.hpp b/ameteor/include/ameteor/graphics/bglayer.hpp
index 1409929..48d19ff 100644
--- a/ameteor/include/ameteor/graphics/bglayer.hpp
+++ b/ameteor/include/ameteor/graphics/bglayer.hpp
@@ -46,6 +46,9 @@ namespace AMeteor
void DrawLine4 (uint8_t line, uint16_t* ptr,
int32_t curX, int32_t curY,
int16_t dx, int16_t dmx, int16_t dy, int16_t dmy, bool frame1);
+ void DrawLine5 (uint16_t* ptr,
+ int32_t refX, int32_t refY,
+ int16_t dx, int16_t dy, bool frame1);
void FillList ();
void UpdateCnt (uint16_t cnt);
diff --git a/ameteor/include/ameteor/io.hpp b/ameteor/include/ameteor/io.hpp
index 5f553c0..108e41f 100644
--- a/ameteor/include/ameteor/io.hpp
+++ b/ameteor/include/ameteor/io.hpp
@@ -208,8 +208,11 @@ namespace AMeteor
bool SaveState (std::ostream& stream);
bool LoadState (std::istream& stream);
+ bool GetPolled() { return m_polled; }
+ void SetPolled(bool f) { m_polled = f; }
private :
uint8_t* m_iomem;
+ bool m_polled;
};
}
diff --git a/ameteor/include/ameteor/memory.hpp b/ameteor/include/ameteor/memory.hpp
index a45652d..e3d1aa4 100644
--- a/ameteor/include/ameteor/memory.hpp
+++ b/ameteor/include/ameteor/memory.hpp
@@ -25,6 +25,7 @@
#include <string>
#include <istream>
#include <ostream>
+#include <map>
namespace AMeteor
{
@@ -119,6 +120,7 @@ namespace AMeteor
void TimeEvent ();
+ std::map<std::string, std::pair<uint8_t*, size_t> > GetMemories();
private :
// times for a 8 or 16 bits access
uint8_t m_memtime[0xF];
diff --git a/ameteor/source/clock.cpp b/ameteor/source/clock.cpp
index 7f21980..460db6a 100644
--- a/ameteor/source/clock.cpp
+++ b/ameteor/source/clock.cpp
@@ -35,12 +35,11 @@ namespace AMeteor
{
unsigned short tocommit;
- m_count += m_cycles;
-
// this loop is here because a timer can trigger a dma which will take a
// long time, during this time the lcd must draw and the timers continue
while (m_cycles >= m_first)
{
+ m_count += m_cycles;
tocommit = m_cycles;
m_cycles = 0;
diff --git a/ameteor/source/graphics/bglayer.cpp b/ameteor/source/graphics/bglayer.cpp
index 72eea70..2c9eea4 100644
--- a/ameteor/source/graphics/bglayer.cpp
+++ b/ameteor/source/graphics/bglayer.cpp
@@ -133,11 +133,11 @@ namespace AMeteor
else
*ptr = 0x0;
- if (flipH)
- --tpChar;
- else
- ++tpChar;
}
+ if (flipH)
+ --tpChar;
+ else
+ ++tpChar;
++ptr;
++tileX;
@@ -186,27 +186,27 @@ namespace AMeteor
// we draw until the end of the tile or the line
while (tileX < 8)
{
+ if (flipH)
+ if (tileX % 2)
+ {
+ colorInd = *tpChar & 0xF;
+ --tpChar;
+ }
+ else
+ colorInd = *tpChar >> 4;
+ else
+ if (tileX % 2)
+ {
+ colorInd = *tpChar >> 4;
+ ++tpChar;
+ }
+ else
+ colorInd = *tpChar & 0xF;
+
if (mosH && i % mosH)
*ptr = ptr[-1];
else
{
- if (flipH)
- if (tileX % 2)
- {
- colorInd = *tpChar & 0xF;
- --tpChar;
- }
- else
- colorInd = *tpChar >> 4;
- else
- if (tileX % 2)
- {
- colorInd = *tpChar >> 4;
- ++tpChar;
- }
- else
- colorInd = *tpChar & 0xF;
-
if (colorInd)
*ptr = pPalette[colorInd] | 0x8000;
else
@@ -309,7 +309,7 @@ namespace AMeteor
{
int32_t intX, intY;
- uint8_t* pChar = m_memory.GetRealAddress(0x06000000);
+ uint16_t* pChar = (uint16_t*)m_memory.GetRealAddress(0x06000000);
for (uint8_t x = 0; x < 240; ++x, ++ptr, curX += dx, curY += dy)
{
@@ -318,25 +318,9 @@ namespace AMeteor
// if we are off layer
if (intX < 0 || intX >= 240)
- if (m_cnt & (0x1 << 13))
- {
- // NOTE : in C++, the modulus can be negative
- intX %= 240;
- if (intX < 0)
- intX += 240;
- }
- else
- continue;
+ continue;
if (intY < 0 || intY >= 160)
- if (m_cnt & (0x1 << 13))
- {
- intY %= 160;
- if (intY < 0)
- intY += 160;
- }
- else
- continue;
-
+ continue;
*ptr = pChar[intY * 240 * 2 + intX * 2] | 0x8000;
}
}
@@ -413,6 +397,27 @@ namespace AMeteor
}
}
+ void BgLayer::DrawLine5 (uint16_t* ptr,
+ int32_t curX, int32_t curY,
+ int16_t dx, int16_t dy, bool frame1)
+ {
+ int32_t intX, intY;
+ uint16_t* pChar = (uint16_t*) m_memory.GetRealAddress(frame1 ? 0x0600A000 : 0x06000000);
+
+ for (uint8_t x = 0; x < 240; ++x, ++ptr, curX += dx, curY += dy)
+ {
+ intX = curX >> 8;
+ intY = curY >> 8;
+
+ // if we are off layer
+ if (intX < 0 || intX >= 160)
+ continue;
+ if (intY < 0 || intY >= 128)
+ continue;
+ *ptr = pChar[intY * 160 + intX] | 0x8000;
+ }
+ }
+
void BgLayer::UpdateCnt (uint16_t cnt)
{
if (m_cnt == cnt)
diff --git a/ameteor/source/graphics/screen.cpp b/ameteor/source/graphics/screen.cpp
index 4c5628b..85da3b9 100644
--- a/ameteor/source/graphics/screen.cpp
+++ b/ameteor/source/graphics/screen.cpp
@@ -121,6 +121,16 @@ namespace AMeteor
// if objects are enabled draw them
if (layersOn & (0x1 << 4)) m_objs.DrawLine(line, lineObj);
break;
+ case 3: // bg2 only 15 bit direct color 240x160
+ layersOn &= 0xF4;
+ if (layersOn & (0x1 << 2))
+ m_bgLayer2.DrawLine3(lineBg+2*WIDTH,
+ m_refX2, m_refY2,
+ m_io.DRead16(Io::BG2PA),
+ m_io.DRead16(Io::BG2PC));
+ if (layersOn & (0x1 << 4))
+ m_objs.DrawLineHighOnly(line, lineObj);
+ break;
// TODO (remember, HIGH ONLY for objs, don't make shitty copy paste)
case 4: // bg2 only in mode 4 (bitmap 256)
layersOn &= 0xF4;
@@ -141,6 +151,18 @@ namespace AMeteor
// all objs with the current priority
m_objs.DrawLineHighOnly(line, lineObj);
break;
+ case 5: // bg2 only 15 bit direct color 160x128 2 frames
+ layersOn &= 0xF4;
+ if (layersOn & (0x1 << 2))
+ m_bgLayer2.DrawLine5(lineBg+2*WIDTH,
+ m_refX2, m_refY2,
+ m_io.DRead16(Io::BG2PA),
+ m_io.DRead16(Io::BG2PC),
+ m_dispcnt & (0x1 << 4));
+
+ if (layersOn & (0x1 << 4))
+ m_objs.DrawLineHighOnly(line, lineObj);
+ break;
default :
met_abort("not supported : " << (m_dispcnt & 0x7));
break;
diff --git a/ameteor/source/io.cpp b/ameteor/source/io.cpp
index c0cd244..2003d21 100644
--- a/ameteor/source/io.cpp
+++ b/ameteor/source/io.cpp
@@ -99,6 +99,8 @@ namespace AMeteor
// TODO implement unreadable or write-only io
uint8_t Io::Read8 (uint32_t add)
{
+ if ((add & 0xFFF) == KEYINPUT)
+ m_polled = true;
//debug ("IO Read8 at " << IOS_ADD << add << " of " << IOS_ADD << (int)*(uint8_t*)(m_iomem + (add & 0xFFF)));
if ((add & 0xFF0) == 0x100)
switch (add & 0xF)
@@ -114,6 +116,8 @@ namespace AMeteor
uint16_t Io::Read16 (uint32_t add)
{
+ if ((add & 0xFFE) == KEYINPUT)
+ m_polled = true;
//debug ("IO Read16 at " << IOS_ADD << add << " of " << IOS_ADD << *(uint16_t*)(m_iomem + (add & 0xFFF)));
// special case, reading timers
if ((add & 0xFF0) == 0x100)
@@ -129,6 +133,8 @@ namespace AMeteor
uint32_t Io::Read32 (uint32_t add)
{
+ if ((add & 0xFFC) == KEYINPUT)
+ m_polled = true;
//debug ("IO Read32 at " << IOS_ADD << add << " of " << IOS_ADD << *(uint32_t*)(m_iomem + (add & 0xFFF)));
// special case, reading timers
if ((add & 0xFF0) == 0x100)
@@ -282,29 +288,36 @@ namespace AMeteor
// update the vcounter flag and eventually trigger an interrupt
W16(add, (val & 0xFFF8) | (m_iomem[add & 0xFFF] & 0x07));
break;
- // The BG*OFS are write-only, we don't need to W16()
case BG0HOFS:
+ W16(add, val & 0x1FF);
LCD.UpdateBg0XOff(val & 0x1FF);
break;
case BG0VOFS:
+ W16(add, val & 0x1FF);
LCD.UpdateBg0YOff(val & 0x1FF);
break;
case BG1HOFS:
+ W16(add, val & 0x1FF);
LCD.UpdateBg1XOff(val & 0x1FF);
break;
case BG1VOFS:
+ W16(add, val & 0x1FF);
LCD.UpdateBg1YOff(val & 0x1FF);
break;
case BG2HOFS:
+ W16(add, val & 0x1FF);
LCD.UpdateBg2XOff(val & 0x1FF);
break;
case BG2VOFS:
+ W16(add, val & 0x1FF);
LCD.UpdateBg2YOff(val & 0x1FF);
break;
case BG3HOFS:
+ W16(add, val & 0x1FF);
LCD.UpdateBg3XOff(val & 0x1FF);
break;
case BG3VOFS:
+ W16(add, val & 0x1FF);
LCD.UpdateBg3YOff(val & 0x1FF);
break;
case BG2X_H:
diff --git a/ameteor/source/memory.cpp b/ameteor/source/memory.cpp
index bf17688..839841e 100644
--- a/ameteor/source/memory.cpp
+++ b/ameteor/source/memory.cpp
@@ -464,8 +464,9 @@ namespace AMeteor
// write if we have a custom bios and write it too
bool b = m_brom;
SS_WRITE_VAR(b);
- if (b)
+ if (b) {
SS_WRITE_DATA(m_brom, 0x00004000);
+ }
SS_WRITE_DATA(m_wbram, 0x00040000);
SS_WRITE_DATA(m_wcram, 0x00008000);
SS_WRITE_DATA(m_pram , 0x00000400);
@@ -490,9 +491,9 @@ namespace AMeteor
// read if we have a custom bios and write it too
bool b;
SS_READ_VAR(b);
- if (b)
+ if (b) {
SS_READ_DATA(m_brom , 0x00004000);
- else
+ } else
UnloadBios();
SS_READ_DATA(m_wbram, 0x00040000);
SS_READ_DATA(m_wcram, 0x00008000);
@@ -532,6 +533,8 @@ namespace AMeteor
if (!r)
{
debugm("Unknown address for Read8 : " << IOS_ADD << add);
+ if(add == R(15))
+ return 0xFF; //We are fucked...
// FIXME : in arm state, vba returns read8(r15 + (add & 3))
// and in thumb read8(r15 + (add & 1))
return Read8(R(15));
@@ -559,8 +562,10 @@ namespace AMeteor
if (!r)
{
debugm("Unknown address for Read16 : " << IOS_ADD << add);
- if (R(15) == add)
+ if (R(15) == add) {
met_abort("Illegal PC");
+ return 0xFFFF; //We are fucked.
+ }
// FIXME : in arm state, vba returns read16(r15 + (add & 2))
return Read16(R(15));
}
@@ -586,8 +591,10 @@ namespace AMeteor
if (!r)
{
debugm("Unknown address for Read32 : " << IOS_ADD << add);
- if (R(15) == add)
+ if (R(15) == add) {
met_abort("Illegal PC");
+ return 0xFFFFFFFFU; //We are fucked.
+ }
if (FLAG_T)
{
uint16_t o = Read16(R(15));
@@ -810,4 +817,20 @@ namespace AMeteor
if (m_cart->Write(add, val))
CLOCK.SetBattery(CART_SAVE_TIME);
}
+
+ std::map<std::string, std::pair<uint8_t*, size_t> > Memory::GetMemories()
+ {
+ std::map<std::string, std::pair<uint8_t*, size_t> > x;
+ if(m_brom)
+ x["brom"] = std::make_pair(m_brom, 0x00004000);
+ x["wbram"] = std::make_pair(m_wbram, 0x00040000);
+ x["wcram"] = std::make_pair(m_wcram, 0x00008000);
+ x["pram"] = std::make_pair(m_pram, 0x00000400);
+ x["vram"] = std::make_pair(m_vram, 0x00018000);
+ x["oam"] = std::make_pair(m_oram, 0x00000400);
+ if(m_cart)
+ x["sram"] = std::make_pair(m_cart->GetRawData(), m_cart->GetRawSize());
+ x["rom"] = std::make_pair(m_rom, 0x02000000);
+ return x;
+ }
}
--
1.7.9.48.g85da4d

View file

@ -106,6 +106,9 @@ BUILD_GAMBATTE=
# Set to non-empty value (e.g. 'yes') to build the bsnes core.
BUILD_BSNES=yes
# Set to non-empty value (e.g. 'yes') to build the meteor core.
BUILD_METEOR=
# Set to non-empty value (e.g. 'yes') if bsnes build uses compatiblity core, not accuracy core.
BSNES_IS_COMPAT=

View file

@ -1,4 +1,4 @@
CORES=bsnes-legacy gambatte sky test
CORES=bsnes-legacy gambatte sky test meteor
ALLFILES=__all__.files
ALLFLAGS=__all__.ldflags
CORES_FILES=$(patsubst %,%/$(ALLFILES),$(CORES))
@ -23,6 +23,9 @@ sky/$(ALLFILES): forcelook make-ports.exe
test/$(ALLFILES): forcelook make-ports.exe
$(MAKE) -C test
meteor/$(ALLFILES): forcelook
$(MAKE) -C meteor
.PRECIOUS: %.$(OBJECT_SUFFIX) %.files
precheck:
@ -30,11 +33,13 @@ precheck:
$(MAKE) -C gambatte precheck
$(MAKE) -C sky precheck
$(MAKE) -C test precheck
$(MAKE) -C meteor precheck
clean:
rm -f *.$(OBJECT_SUFFIX) __all__.ldflags __all__.files
$(MAKE) -C bsnes-legacy clean
$(MAKE) -C gambatte clean
$(MAKE) -C meteor clean
$(MAKE) -C sky clean
$(MAKE) -C test clean
rm -f make-ports.exe

View file

@ -0,0 +1,42 @@
ifdef BUILD_METEOR
OBJECTS=core.$(OBJECT_SUFFIX)
METEOR_CFLAGS=
METEOR_LDFLAGS=
REALAR=$(CROSS_PREFIX)ar
export REALAR
METEOR_LIBRARY=meteor/libmeteor.$(ARCHIVE_SUFFIX)
.PRECIOUS: %.$(OBJECT_SUFFIX) %.files
__all__.files: $(OBJECTS) ../../../$(METEOR_LIBRARY)
lua ../../genfilelist.lua $^ >$@
echo $(METEOR_LDFLAGS) ../$(METEOR_LIBRARY) >__all__.ldflags
../../../$(METEOR_LIBRARY): forcelook
$(MAKE) -C ../../../meteor
$(REALRANLIB) $@
ports.inc: ports.json ../make-ports.exe
../make-ports.exe <$< >$@
%.$(OBJECT_SUFFIX): %.cpp ports.inc
$(REALCC) -c -o $@ $< -I../../../include -I../../../meteor/ameteor/include $(CFLAGS) $(METEOR_CFLAGS)
else
OBJECTS=
__all__.files: $(OBJECTS)
lua ../../genfilelist.lua $^ >$@
echo >__all__.ldflags
endif
forcelook:
@true
precheck:
@true
clean:
-make -C ../../../gambatte clean
rm -f *.$(OBJECT_SUFFIX) __all__.ldflags __all__.files

View file

@ -0,0 +1,497 @@
/***************************************************************************
* Copyright (C) 2013 by Ilari Liusvaara *
* *
* 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 "lsnes.hpp"
#include <sstream>
#include <iostream>
#include <map>
#include <string>
#include <vector>
#include "core/audioapi.hpp"
#include "core/misc.hpp"
#include "core/command.hpp"
#include "core/controllerframe.hpp"
#include "core/dispatch.hpp"
#include "core/framebuffer.hpp"
#include "core/window.hpp"
#include "interface/callbacks.hpp"
#include "interface/cover.hpp"
#include "interface/romtype.hpp"
#include "library/framebuffer-pixfmt-rgb15.hpp"
#include "library/string.hpp"
//#include "library/portfn.hpp"
#include "library/serialization.hpp"
#include "library/minmax.hpp"
#include "library/framebuffer.hpp"
#define __LIBRETRO__
#include "ameteor.hpp"
#include "ameteor/cartmem.hpp"
uint64_t get_utime();
namespace
{
bool do_reset_flag = false;
bool internal_rom = false;
bool rtc_fixed;
time_t rtc_fixed_val;
std::vector<unsigned char> romdata;
uint16_t cover_fbmem[720 * 480];
bool pflag = false;
int16_t soundbuf[65536];
size_t soundbuf_fill;
bool frame_happened;
bool just_reset;
struct interface_device_reg gba_registers[] = {
{NULL, NULL, NULL}
};
//Framebuffer.
struct framebuffer::info cover_fbinfo = {
&framebuffer::pixfmt_rgb15, //Format.
(char*)cover_fbmem, //Memory.
720, 480, 1440, //Physical size.
720, 480, 1440, //Logical size.
0, 0 //Offset.
};
#include "ports.inc"
struct _output
{
void frame(const uint16_t* p)
{
AMeteor::Stop();
framebuffer::info inf;
inf.type = &framebuffer::pixfmt_rgb15;
inf.mem = const_cast<char*>(reinterpret_cast<const char*>(p));
inf.physwidth = 240;
inf.physheight = 160;
inf.physstride = 480;
inf.width = 240;
inf.height = 160;
inf.stride = 480;
inf.offset_x = 0;
inf.offset_y = 0;
framebuffer::raw ls(inf);
ecore_callbacks->output_frame(ls, 262144, 4389);
ecore_callbacks->timer_tick(4389, 262144);
static uint32_t refreshes = 0;
static uint64_t samples = 0;
refreshes++;
static double srate = 4194304.0/95.0;
if(soundbuf_fill > 0) {
samples += soundbuf_fill / 2;
audioapi_submit_buffer(soundbuf, soundbuf_fill / 2, true, srate);
soundbuf_fill = 0;
}
frame_happened = true;
}
void sample(const int16_t* s)
{
soundbuf[soundbuf_fill++] = s[0];
soundbuf[soundbuf_fill++] = s[1];
}
void vblank()
{
}
} output;
std::string fmt_sram_size(uint32_t sram_size)
{
std::string mult = "";
if(sram_size > 1024) {
mult = "k";
sram_size >>= 10;
}
if(sram_size > 1024) {
mult = "M";
sram_size >>= 10;
}
return (stringfmt() << sram_size << mult << "B").str();
}
void meteor_bus_write(uint64_t offset, uint8_t data)
{
uint8_t* m = AMeteor::_memory.GetRealAddress(offset);
if(m) *m = data;
}
uint8_t meteor_bus_read(uint64_t offset)
{
uint8_t* m = AMeteor::_memory.GetRealAddress(offset);
return m ? *m : 0xFF;
}
void avsync_hack()
{
//Hack: Send 223 samples.
for(unsigned i = 0; i < 446; i++)
soundbuf[soundbuf_fill++] = 0;
}
void meteor_poll_buttons()
{
uint16_t x = 0;
for(unsigned i = 0; i < 10; i++)
if(ecore_callbacks->get_input(0, 1, i))
x |= (1 << i);
AMeteor::_keypad.SetPadState(x ^ 0x3FF); //Inverse polarity.
pflag = true;
}
void basic_init()
{
static bool done = false;
if(done)
return;
done = true;
AMeteor::_memory.LoadCartInferred();
AMeteor::_lcd.sig_vblank.connect(syg::mem_fun(output, &_output::vblank));
AMeteor::_lcd.GetScreen().GetRenderer().SetFrameSlot(syg::mem_fun(output, &_output::frame));
AMeteor::_sound.GetSpeaker().SetFrameSlot(syg::mem_fun(output, &_output::sample));
}
controller_set meteor_controllerconfig(std::map<std::string, std::string>& settings)
{
std::map<std::string, std::string> _settings = settings;
controller_set r;
r.ports.push_back(&psystem);
r.logical_map.push_back(std::make_pair(0, 1));
return r;
}
std::pair<uint64_t, uint64_t> meteor_bus_map()
{
return std::make_pair(0x100000000ULL, 0x100000000ULL);
}
void add_vma_mapped(std::list<core_vma_info>& l, const std::string& name, uint64_t base, uint8_t* ram,
size_t ramsize, int endian, bool readonly)
{
core_vma_info v;
v.name = name;
v.base = base;
v.size = ramsize;
v.backing_ram = ram;
v.endian = endian;
v.readonly = readonly;
v.read = NULL;
v.write = NULL;
l.push_back(v);
}
uint64_t get_vmabase(const std::string& name)
{
static std::map<std::string, uint64_t> unknown;
uint64_t unknown_next = 0x200000000ULL;
if(name == "brom") return 0x90000000ULL;
if(name == "wbram") return 0;
if(name == "wcram") return 0x40000ULL;
if(name == "pram") return 0x100000ULL;
if(name == "vram") return 0x110000ULL;
if(name == "oam") return 0x120000ULL;
if(name == "sram") return 0x10000000ULL;
if(name == "rom") return 0x80000000ULL;
//Unknown.
if(!unknown.count(name)) {
unknown[name] = unknown_next;
unknown_next += 0x100000000ULL;
}
return unknown[name];
}
bool is_read_only_vma(const std::string& name)
{
if(name == "wbram") return false;
if(name == "wcram") return false;
if(name == "pram") return false;
if(name == "vram") return false;
if(name == "oam") return false;
if(name == "sram") return false;
//Dunno what this is.
return true;
}
std::list<core_vma_info> get_VMAlist()
{
std::list<core_vma_info> vmas;
if(!internal_rom)
return vmas;
auto mem_map = AMeteor::_memory.GetMemories();
for(auto i : mem_map)
add_vma_mapped(vmas, i.first, get_vmabase(i.first), i.second.first, i.second.second, -1,
is_read_only_vma(i.first));
//Bus mapping.
core_vma_info bus;
bus.name = "BUS";
bus.base = 0x100000000ULL;
bus.size = 0x100000000ULL;
bus.backing_ram = NULL;
bus.endian = -1;
bus.readonly = false;
bus.read = meteor_bus_read;
bus.write = meteor_bus_write;
vmas.push_back(bus);
return vmas;
}
std::set<std::string> meteor_srams()
{
std::set<std::string> s;
if(!internal_rom)
return s;
auto mem_map = AMeteor::_memory.GetMemories();
if(mem_map.count("sram"))
s.insert("sram");
return s;
}
std::string get_cartridge_name()
{
std::ostringstream name;
if(romdata.size() < 192)
return ""; //Bad.
for(unsigned i = 0; i < 12; i++) {
if(romdata[0x0A0 + i])
name << (char)romdata[0xA0 + i];
else
break;
}
name << "[AGB-";
for(unsigned i = 0; i < 4; i++)
name << (char)romdata[0xAC + i];
name << "] (version " << (int)(unsigned char)romdata[0xBC];
if((unsigned char)romdata[0x9C] == 0xA5)
name << "-Debug";
name << ")";
return name.str();
}
void redraw_cover_fbinfo();
struct _meteor_core : public core_core, public core_type, public core_region, public core_sysregion
{
_meteor_core()
: core_core({&psystem}, {{0, "Soft reset", "reset", {}}}),
core_type({{
.iname = "agb",
.hname = "Game Boy Advance",
.id = 0,
.sysname = "GBA",
.bios = NULL,
.regions = {this},
.images = {{"rom", "Cartridge ROM", 1, 0, 0, "gba;agb"}},
.settings = {{"extbios", "Use GBA BIOS", "0", {
{"0", "False", 0},
{"1", "True", 1}
}}},
.core = this,
}}),
core_region({{"world", "World", 0, 0, false, {4389, 262144}, {0}}}),
core_sysregion("magb", *this, *this) {}
std::string c_core_identifier() { return "meteor 1.4.0"; }
bool c_set_region(core_region& region) { return (&region == this); }
std::pair<uint32_t, uint32_t> c_video_rate() { return std::make_pair(262144, 4389); }
std::pair<uint32_t, uint32_t> c_audio_rate() { return std::make_pair(4194304, 95); }
std::map<std::string, std::vector<char>> c_save_sram() throw(std::bad_alloc) {
std::map<std::string, std::vector<char>> s;
if(!internal_rom)
return s;
std::vector<char> sram;
uint32_t realsize = *(uint32_t*)(AMeteor::CartMemData + AMeteor::CartMem::MAX_SIZE);
sram.resize(realsize);
memcpy(&sram[0], AMeteor::CartMemData, realsize);
s["sram"] = sram;
return s;
}
void c_load_sram(std::map<std::string, std::vector<char>>& sram) throw(std::bad_alloc) {
if(!internal_rom)
return;
if(!sram.count("sram")) {
//Don't clear the SRAM descriptor.
memset(AMeteor::CartMemData, 255, AMeteor::CartMem::MAX_SIZE);
return;
}
std::vector<char>& s = sram["sram"];
//Read the size from SRAM descriptor.
uint32_t realsize = *(uint32_t*)(AMeteor::CartMemData + AMeteor::CartMem::MAX_SIZE);
//Don't clear the SRAM descriptor.
memset(AMeteor::CartMemData, 255, AMeteor::CartMem::MAX_SIZE);
if(s.size() != realsize)
messages << "Unexpected SRAM size, expected " << realsize << " got " << s.size()
<< std::endl;
memcpy(AMeteor::CartMemData, &s[0], min((size_t)realsize, s.size()));
}
void c_serialize(std::vector<char>& out) {
if(!internal_rom)
throw std::runtime_error("Can't save without ROM");
std::ostringstream stream;
AMeteor::SaveState(stream);
std::string s = stream.str();
out.resize(s.length());
std::copy(s.begin(), s.end(), out.begin());
}
void c_unserialize(const char* in, size_t insize) {
if(!internal_rom)
throw std::runtime_error("Can't load without ROM");
std::istringstream stream;
stream.str(std::string((char*)in, insize));
AMeteor::LoadState(stream);
do_reset_flag = false;
}
core_region& c_get_region() { return *this; }
void c_power() {}
void c_unload_cartridge() {}
std::pair<uint32_t, uint32_t> c_get_scale_factors(uint32_t width, uint32_t height) {
return std::make_pair(max(720 / width, (uint32_t)1), max(480 / height, (uint32_t)1));
}
void c_install_handler() { magic_flags |= 4; }
void c_uninstall_handler() {}
void c_emulate() {
if(!internal_rom)
return;
int16_t reset = ecore_callbacks->get_input(0, 0, 1);
if(reset) {
AMeteor::Reset(AMeteor::UNIT_ALL & ~AMeteor::UNIT_MEMORY_BIOS &
~AMeteor::UNIT_MEMORY_ROM);
just_reset = true;
messages << "GBA reset" << std::endl;
}
do_reset_flag = false;
meteor_poll_buttons();
frame_happened = false;
if(just_reset) {
avsync_hack();
just_reset = false;
}
while(!frame_happened) {
AMeteor::Run(281000);
if(!frame_happened)
std::cerr << "Warning: Run timeout" << std::endl;
}
}
void c_runtosave() {}
bool c_get_pflag() { return AMeteor::_io.GetPolled(); }
void c_set_pflag(bool _pflag) { AMeteor::_io.SetPolled(_pflag); }
void c_request_reset(long delay, bool hard) { do_reset_flag = true; }
framebuffer::raw& c_draw_cover() {
static framebuffer::raw x(cover_fbinfo);
redraw_cover_fbinfo();
return x;
}
std::string c_get_core_shortname() { return "meteor140"; }
void c_pre_emulate_frame(controller_frame& cf) {
cf.axis3(0, 0, 1, do_reset_flag ? 1 : 0);
}
void c_execute_action(unsigned id, const std::vector<interface_action_paramval>& p)
{
if(id == 0)
do_reset_flag = true;
}
unsigned int c_action_flags(unsigned id)
{
if(id == 0) return 1;
return 0;
}
const interface_device_reg* c_get_registers() { return gba_registers; }
int c_reset_action(bool hard) { return hard ? -1 : 0; }
int t_load_rom(core_romimage* img, std::map<std::string, std::string>& settings, uint64_t rtc_sec,
uint64_t rtc_subsec) {
uint32_t sram_size = 0;
std::map<std::string, std::string> _settings = settings;
get_settings().fill_defaults(_settings);
basic_init();
const char* markup = img[0].markup;
if(!markup)
markup = "";
std::string _markup = markup;
std::istringstream imarkup(markup);
const unsigned char* data = img[0].data;
size_t size = img[0].size;
romdata.resize(size);
memcpy(&romdata[0], data, size);
std::string markup_line;
while(std::getline(imarkup, markup_line)) {
regex_results r;
istrip_CR(markup_line);
if(r = regex("sram_size=([0-9]+)", markup_line)) {
try {
sram_size = parse_value<uint32_t>(r[1]);
} catch(...) {
}
} else if(r = regex("sram_size=([0-9]+)k", markup_line)) {
try {
sram_size = 1024 * parse_value<uint32_t>(r[1]);
} catch(...) {
}
} else
messages << "Unknown markup: " << markup_line << std::endl;
}
AMeteor::Reset(AMeteor::UNIT_ALL);
if(_settings["extbios"] != "0") {
//Load the BIOS.
std::string bname = ecore_callbacks->get_firmware_path() + "/gbabios.bin";
if(!AMeteor::_memory.LoadBios(bname.c_str())) {
messages << "Can't load GBA BIOS" << std::endl;
return -1;
}
}
AMeteor::_memory.LoadRom((const uint8_t*)data, size);
*(uint32_t*)(AMeteor::CartMemData + AMeteor::CartMem::MAX_SIZE) = sram_size;
if(sram_size > 0)
messages << "SRAM size: " << fmt_sram_size(sram_size) << std::endl;
AMeteor::_memory.LoadCartInferred();
internal_rom = true;
do_reset_flag = false;
just_reset = true;
return 0;
}
controller_set t_controllerconfig(std::map<std::string, std::string>& settings)
{
return meteor_controllerconfig(settings);
}
std::pair<uint64_t, uint64_t> c_get_bus_map() { return meteor_bus_map(); }
std::list<core_vma_info> c_vma_list() { return get_VMAlist(); }
std::set<std::string> c_srams() { return meteor_srams(); }
double c_get_PAR() { return 1.0; }
void c_set_debug_flags(uint64_t addr, unsigned flags_set, unsigned flags_clear) {}
void c_set_cheat(uint64_t addr, uint64_t value, bool set) {}
std::vector<std::string> c_get_trace_cpus() { return std::vector<std::string>(); }
void c_debug_reset() {}
} meteor_core;
void redraw_cover_fbinfo()
{
for(size_t i = 0; i < sizeof(cover_fbmem) / sizeof(cover_fbmem[0]); i++)
cover_fbmem[i] = 0x0000;
std::string ident = meteor_core.c_core_identifier();
cover_render_string(cover_fbmem, 0, 0, ident, 0xFFFF, 0x0000, 720, 480, 1440, 2);
cover_render_string(cover_fbmem, 0, 16, "Internal ROM name: " + get_cartridge_name(), 0xFFFF, 0x0000,
720, 480, 1440, 2);
unsigned y = 32;
for(auto i : cover_information()) {
cover_render_string(cover_fbmem, 0, y, i, 0xFFFF, 0x0000, 720, 480, 1440, 2);
y += 16;
}
}
}

View file

@ -0,0 +1,25 @@
{
"ports":[{
"symbol":"psystem", "name":"system", "hname":"system","controllers":[{
"type":"(system)", "class":"(system)","buttons":[
{"type":"button","symbol":"F","name":"framesync", "shadow":true},
{"type":"button","symbol":"R","name":"reset", "shadow":true},
{"type":"null", "shadow":true},
{"type":"null", "shadow":true}
]
},{
"type":"gamepad", "class":"gba","buttons":[
{"type":"button","name":"A"},
{"type":"button","name":"B"},
{"type":"button","symbol":"s","name":"select"},
{"type":"button","symbol":"S","name":"start"},
{"type":"button","movie":"r","symbol":"→","name":"right","macro":">"},
{"type":"button","movie":"l","symbol":"←","name":"left","macro":"<"},
{"type":"button","movie":"u","symbol":"↑","name":"up","macro":"^"},
{"type":"button","movie":"d","symbol":"↓","name":"down","macro":"v"},
{"type":"button","name":"L"},
{"type":"button","name":"R"}
]
}],"legal":[0]
}]
}