feat: add thirty emulator profiles and their data

Thirty profiles from the ES-DE batch, each source-verified by the
session that wrote it and passing the schema and semantic checks. Five
declare no files at all and say why in notes referenced to the code:
NGP.emu, openbor, Plastic, Swan.emu and XeniOS.

Twenty-eight files come with them, every one declared by the profile
that needs it and matching the hash it declares, with no duplicate of
anything already held: the NetherSX2 Turnip Classic assets, the Speccy
machine ROMs, the Virtual Boy homebrew the app bundles, Snes9x EX+'s
bundled game, and sixtyforce's Overrides.plist, which carries a size
and no hash because the binary never checks one.

supermodel gains the four data files it reads from its install tree,
hakux marks its controller map unsourceable now that the asset manager
is known to read inside the package, and nethersx2 sheds the two core
aliases that belong to the Turnip profiles.
This commit is contained in:
Abdessamad Derraz committed 2026-08-23 09:05:35 +02:00
1 parent 87ff398f9a
commit e42d0815c1
61 files changed
+154724 -7

No files matched your search

File diff suppressed because it is too large. Load diff
@@ -0,0 +1,107 @@
//#version 420 // Keep it for editor detection
//////////////////////////////////////////////////////////////////////
// Common Interface Definition
//////////////////////////////////////////////////////////////////////
#ifdef VERTEX_SHADER
#if !pGL_ES
out gl_PerVertex {
vec4 gl_Position;
float gl_PointSize;
#if !pGL_ES
float gl_ClipDistance[1];
#endif
};
#endif
#endif
#ifdef GEOMETRY_SHADER
#if !pGL_ES
in gl_PerVertex {
vec4 gl_Position;
float gl_PointSize;
#if !pGL_ES
float gl_ClipDistance[1];
#endif
} gl_in[];
out gl_PerVertex {
vec4 gl_Position;
float gl_PointSize;
#if !pGL_ES
float gl_ClipDistance[1];
#endif
};
#endif
#endif
//////////////////////////////////////////////////////////////////////
// Constant Buffer Definition
//////////////////////////////////////////////////////////////////////
// Performance note, some drivers (nouveau) will validate all Constant Buffers
// even if only one was updated.
#if defined(VERTEX_SHADER) || defined(GEOMETRY_SHADER)
layout(std140, binding = 1) uniform cb20
{
vec2 VertexScale;
vec2 VertexOffset;
vec2 TextureScale;
vec2 TextureOffset;
vec2 PointSize;
uint MaxDepth;
uint pad_cb20;
};
#endif
#if defined(VERTEX_SHADER) || defined(FRAGMENT_SHADER)
layout(std140, binding = 0) uniform cb21
{
vec3 FogColor;
float AREF;
vec4 WH;
vec2 TA;
float MaxDepthPS;
float Af;
uvec4 MskFix;
uvec4 FbMask;
vec4 HalfTexel;
vec4 MinMax;
ivec4 ChannelShuffle;
vec2 TC_OffsetHack;
vec2 STScale;
mat4 DitherMatrix;
};
#endif
//layout(std140, binding = 22) uniform cb22
//{
// vec4 rt_size;
//};
//////////////////////////////////////////////////////////////////////
// Default Sampler
//////////////////////////////////////////////////////////////////////
#ifdef FRAGMENT_SHADER
layout(binding = 0) uniform sampler2D TextureSampler;
#endif
@@ -0,0 +1,387 @@
//#version 420 // Keep it for editor detection
#ifdef VERTEX_SHADER
layout(location = 0) in vec2 POSITION;
layout(location = 1) in vec2 TEXCOORD0;
layout(location = 7) in vec4 COLOR;
// FIXME set the interpolation (don't know what dx do)
// flat means that there is no interpolation. The value given to the fragment shader is based on the provoking vertex conventions.
//
// noperspective means that there will be linear interpolation in window-space. This is usually not what you want, but it can have its uses.
//
// smooth, the default, means to do perspective-correct interpolation.
//
// The centroid qualifier only matters when multisampling. If this qualifier is not present, then the value is interpolated to the pixel's center, anywhere in the pixel, or to one of the pixel's samples. This sample may lie outside of the actual primitive being rendered, since a primitive can cover only part of a pixel's area. The centroid qualifier is used to prevent this; the interpolation point must fall within both the pixel's area and the primitive's area.
out vec4 PSin_p;
out vec2 PSin_t;
out vec4 PSin_c;
void vs_main()
{
PSin_p = vec4(POSITION, 0.5f, 1.0f);
PSin_t = TEXCOORD0;
PSin_c = COLOR;
gl_Position = vec4(POSITION, 0.5f, 1.0f); // NOTE I don't know if it is possible to merge POSITION_OUT and gl_Position
}
#endif
#ifdef FRAGMENT_SHADER
in vec4 PSin_p;
in vec2 PSin_t;
in vec4 PSin_c;
// Give a different name so I remember there is a special case!
#if defined(ps_convert_rgba8_16bits) || defined(ps_convert_float32_32bits)
layout(location = 0) out uint SV_Target1;
#else
layout(location = 0) out vec4 SV_Target0;
#endif
vec4 sample_c()
{
return texture(TextureSampler, PSin_t);
}
#ifdef ps_copy
void ps_copy()
{
SV_Target0 = sample_c();
}
#endif
#ifdef ps_depth_copy
void ps_depth_copy()
{
gl_FragDepth = sample_c().r;
}
#endif
#ifdef ps_convert_rgba8_16bits
// Need to be careful with precision here, it can break games like Spider-Man 3 and Dogs Life
void ps_convert_rgba8_16bits()
{
highp uvec4 i = uvec4(sample_c() * vec4(255.5f, 255.5f, 255.5f, 255.5f));
SV_Target1 = ((i.x & 0x00F8u) >> 3) | ((i.y & 0x00F8u) << 2) | ((i.z & 0x00f8u) << 7) | ((i.w & 0x80u) << 8);
}
#endif
#ifdef ps_convert_float32_32bits
void ps_convert_float32_32bits()
{
// Convert a GL_FLOAT32 depth texture into a 32 bits UINT texture
#if HAS_CLIP_CONTROL
SV_Target1 = uint(exp2(32.0f) * sample_c().r);
#else
SV_Target1 = uint(exp2(24.0f) * sample_c().r);
#endif
}
#endif
#ifdef ps_convert_float32_rgba8
void ps_convert_float32_rgba8()
{
// Convert a GL_FLOAT32 depth texture into a RGBA color texture
#if HAS_CLIP_CONTROL
uint d = uint(sample_c().r * exp2(32.0f));
#else
uint d = uint(sample_c().r * exp2(24.0f));
#endif
SV_Target0 = vec4(uvec4((d & 0xFFu), ((d >> 8) & 0xFFu), ((d >> 16) & 0xFFu), (d >> 24))) / vec4(255.0);
}
#endif
#ifdef ps_convert_float16_rgb5a1
void ps_convert_float16_rgb5a1()
{
// Convert a GL_FLOAT32 (only 16 lsb) depth into a RGB5A1 color texture
#if HAS_CLIP_CONTROL
uint d = uint(sample_c().r * exp2(32.0f));
#else
uint d = uint(sample_c().r * exp2(24.0f));
#endif
SV_Target0 = vec4(uvec4((d & 0x1Fu), ((d >> 5) & 0x1Fu), ((d >> 10) & 0x1Fu), (d >> 15) & 0x01u)) / vec4(32.0f, 32.0f, 32.0f, 1.0f);
}
#endif
float rgba8_to_depth32(vec4 unorm)
{
uvec4 c = uvec4(unorm * vec4(255.5f));
#if HAS_CLIP_CONTROL
return float(c.r | (c.g << 8) | (c.b << 16) | (c.a << 24)) * exp2(-32.0f);
#else
return float(c.r | (c.g << 8) | (c.b << 16) | (c.a << 24)) * exp2(-24.0f);
#endif
}
float rgba8_to_depth24(vec4 unorm)
{
uvec3 c = uvec3(unorm.rgb * vec3(255.5f));
#if HAS_CLIP_CONTROL
return float(c.r | (c.g << 8) | (c.b << 16)) * exp2(-32.0f);
#else
return float(c.r | (c.g << 8) | (c.b << 16)) * exp2(-24.0f);
#endif
}
float rgba8_to_depth16(vec4 unorm)
{
uvec2 c = uvec2(unorm.rg * vec2(255.5f));
#if HAS_CLIP_CONTROL
return float(c.r | (c.g << 8)) * exp2(-32.0f);
#else
return float(c.r | (c.g << 8)) * exp2(-24.0f);
#endif
}
float rgb5a1_to_depth16(vec4 unorm)
{
uvec4 c = uvec4(unorm * vec4(255.5f));
#if HAS_CLIP_CONTROL
return float(((c.r & 0xF8u) >> 3) | ((c.g & 0xF8u) << 2) | ((c.b & 0xF8u) << 7) | ((c.a & 0x80u) << 8)) * exp2(-32.0f);
#else
return float(((c.r & 0xF8u) >> 3) | ((c.g & 0xF8u) << 2) | ((c.b & 0xF8u) << 7) | ((c.a & 0x80u) << 8)) * exp2(-24.0f);
#endif
}
#ifdef ps_convert_rgba8_float32
void ps_convert_rgba8_float32()
{
// Convert an RGBA texture into a float depth texture
gl_FragDepth = rgba8_to_depth32(sample_c());
}
#endif
#ifdef ps_convert_rgba8_float24
void ps_convert_rgba8_float24()
{
// Same as above but without the alpha channel (24 bits Z)
// Convert an RGBA texture into a float depth texture
gl_FragDepth = rgba8_to_depth24(sample_c());
}
#endif
#ifdef ps_convert_rgba8_float16
void ps_convert_rgba8_float16()
{
// Same as above but without the A/B channels (16 bits Z)
// Convert an RGBA texture into a float depth texture
gl_FragDepth = rgba8_to_depth16(sample_c());
}
#endif
#ifdef ps_convert_rgb5a1_float16
void ps_convert_rgb5a1_float16()
{
// Convert an RGB5A1 (saved as RGBA8) color to a 16 bit Z
gl_FragDepth = rgb5a1_to_depth16(sample_c());
}
#endif
#define SAMPLE_RGBA_DEPTH_BILN(CONVERT_FN) \
ivec2 dims = textureSize(TextureSampler, 0); \
vec2 top_left_f = PSin_t * vec2(dims) - 0.5f; \
ivec2 top_left = ivec2(floor(top_left_f)); \
ivec4 coords = clamp(ivec4(top_left, top_left + 1), ivec4(0), dims.xyxy - 1); \
vec2 mix_vals = fract(top_left_f); \
float depthTL = CONVERT_FN(texelFetch(TextureSampler, coords.xy, 0)); \
float depthTR = CONVERT_FN(texelFetch(TextureSampler, coords.zy, 0)); \
float depthBL = CONVERT_FN(texelFetch(TextureSampler, coords.xw, 0)); \
float depthBR = CONVERT_FN(texelFetch(TextureSampler, coords.zw, 0)); \
gl_FragDepth = mix(mix(depthTL, depthTR, mix_vals.x), mix(depthBL, depthBR, mix_vals.x), mix_vals.y);
#ifdef ps_convert_rgba8_float32_biln
void ps_convert_rgba8_float32_biln()
{
// Convert an RGBA texture into a float depth texture
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth32);
}
#endif
#ifdef ps_convert_rgba8_float24_biln
void ps_convert_rgba8_float24_biln()
{
// Same as above but without the alpha channel (24 bits Z)
// Convert an RGBA texture into a float depth texture
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth24);
}
#endif
#ifdef ps_convert_rgba8_float16_biln
void ps_convert_rgba8_float16_biln()
{
// Same as above but without the A/B channels (16 bits Z)
// Convert an RGBA texture into a float depth texture
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth16);
}
#endif
#ifdef ps_convert_rgb5a1_float16_biln
void ps_convert_rgb5a1_float16_biln()
{
// Convert an RGB5A1 (saved as RGBA8) color to a 16 bit Z
SAMPLE_RGBA_DEPTH_BILN(rgb5a1_to_depth16);
}
#endif
#ifdef ps_convert_rgba_8i
void ps_convert_rgba_8i()
{
// Convert a RGBA texture into a 8 bits packed texture
// Input column: 8x2 RGBA pixels
// 0: 8 RGBA
// 1: 8 RGBA
// Output column: 16x4 Index pixels
// 0: 8 R | 8 B
// 1: 8 R | 8 B
// 2: 8 G | 8 A
// 3: 8 G | 8 A
uvec2 pos = uvec2(gl_FragCoord.xy);
// Collapse separate R G B A areas into their base pixel
uvec2 block = (pos & ~uvec2(15u, 3u)) >> 1;
uvec2 subblock = pos & uvec2(7u, 1u);
uvec2 coord = block | subblock;
// Apply offset to cols 1 and 2
uint is_col23 = pos.y & 4u;
uint is_col13 = pos.y & 2u;
uint is_col12 = is_col23 ^ (is_col13 << 1);
coord.x ^= is_col12; // If cols 1 or 2, flip bit 3 of x
if (floor(PS_SCALE_FACTOR) != PS_SCALE_FACTOR)
coord = uvec2(vec2(coord) * PS_SCALE_FACTOR);
else
coord *= uvec2(PS_SCALE_FACTOR);
vec4 pixel = texelFetch(TextureSampler, ivec2(coord), 0);
vec2 sel0 = (pos.y & 2u) == 0u ? pixel.rb : pixel.ga;
float sel1 = (pos.x & 8u) == 0u ? sel0.x : sel0.y;
SV_Target0 = vec4(sel1);
}
#endif
#ifdef ps_filter_transparency
void ps_filter_transparency()
{
vec4 c = sample_c();
SV_Target0 = vec4(c.rgb, 1.0);
}
#endif
// Used for DATE (stencil)
// DATM == 1
#ifdef ps_datm1
void ps_datm1()
{
if(sample_c().a < (127.5f / 255.0f)) // >= 0x80 pass
discard;
}
#endif
// Used for DATE (stencil)
// DATM == 0
#ifdef ps_datm0
void ps_datm0()
{
if((127.5f / 255.0f) < sample_c().a) // < 0x80 pass (== 0x80 should not pass)
discard;
}
#endif
#ifdef ps_hdr_init
void ps_hdr_init()
{
vec4 value = sample_c();
SV_Target0 = vec4(round(value.rgb * 255.0f) / 65535.0f, value.a);
}
#endif
#ifdef ps_hdr_resolve
void ps_hdr_resolve()
{
vec4 value = sample_c();
SV_Target0 = vec4(vec3(uvec3(value.rgb * 65535.0f) & 255u) / 255.0f, value.a);
}
#endif
#ifdef ps_yuv
uniform ivec2 EMOD;
void ps_yuv()
{
vec4 i = sample_c();
vec4 o;
mat3 rgb2yuv; // Value from GS manual
rgb2yuv[0] = vec3(0.587, -0.311, -0.419);
rgb2yuv[1] = vec3(0.114, 0.500, -0.081);
rgb2yuv[2] = vec3(0.299, -0.169, 0.500);
vec3 yuv = rgb2yuv * i.gbr;
float Y = float(0xDB)/255.0f * yuv.x + float(0x10)/255.0f;
float Cr = float(0xE0)/255.0f * yuv.y + float(0x80)/255.0f;
float Cb = float(0xE0)/255.0f * yuv.z + float(0x80)/255.0f;
switch(EMOD.x) {
case 0:
o.a = i.a;
break;
case 1:
o.a = Y;
break;
case 2:
o.a = Y/2.0f;
break;
case 3:
o.a = 0.0f;
break;
}
switch(EMOD.y) {
case 0:
o.rgb = i.rgb;
break;
case 1:
o.rgb = vec3(Y);
break;
case 2:
o.rgb = vec3(Y, Cb, Cr);
break;
case 3:
o.rgb = vec3(i.a);
break;
}
SV_Target0 = o;
}
#endif
#if defined(ps_stencil_image_init_0) || defined(ps_stencil_image_init_1)
void main()
{
SV_Target0 = vec4(0x7FFFFFFF);
#ifdef ps_stencil_image_init_0
if((127.5f / 255.0f) < sample_c().a) // < 0x80 pass (== 0x80 should not pass)
SV_Target0 = vec4(-1);
#endif
#ifdef ps_stencil_image_init_1
if(sample_c().a < (127.5f / 255.0f)) // >= 0x80 pass
SV_Target0 = vec4(-1);
#endif
}
#endif
#endif
@@ -0,0 +1,993 @@
//#version 420 // Keep it for text editor detection
// Require for bit operation
//#extension GL_ARB_gpu_shader5 : enable
#define FMT_32 0
#define FMT_24 1
#define FMT_16 2
// APITRACE_DEBUG enables forced pixel output to easily detect
// the fragment computed by primitive
#define APITRACE_DEBUG 0
// TEX_COORD_DEBUG output the uv coordinate as color. It is useful
// to detect bad sampling due to upscaling
//#define TEX_COORD_DEBUG
// Just copy directly the texture coordinate
#ifdef TEX_COORD_DEBUG
#define PS_TFX 1
#define PS_TCC 1
#endif
#define SW_BLEND (PS_BLEND_A || PS_BLEND_B || PS_BLEND_D)
#define SW_BLEND_NEEDS_RT (SW_BLEND && (PS_BLEND_A == 1 || PS_BLEND_B == 1 || PS_BLEND_C == 1 || PS_BLEND_D == 1))
#define SW_AD_TO_HW (PS_BLEND_C == 1 && PS_CLR_HW > 3)
#define PS_PRIMID_INIT (PS_DATE == 1 || PS_DATE == 2)
#define NEEDS_RT_EARLY (PS_TEX_IS_FB == 1 || PS_DATE >= 5)
#define NEEDS_RT (NEEDS_RT_EARLY || (!PS_PRIMID_INIT && (PS_FBMASK || SW_BLEND_NEEDS_RT || SW_AD_TO_HW)))
#ifdef FRAGMENT_SHADER
#if !defined(BROKEN_DRIVER) && (pGL_ES || defined(GL_ARB_enhanced_layouts) && GL_ARB_enhanced_layouts)
layout(location = 0)
#endif
in SHADER
{
vec4 t_float;
vec4 t_int;
#if PS_IIP != 0
vec4 c;
#else
flat vec4 c;
#endif
} PSin;
#define TARGET_0_QUALIFIER out
// Only enable framebuffer fetch when we actually need it.
#if HAS_FRAMEBUFFER_FETCH && NEEDS_RT
// We need to force the colour to be defined here, to read from it.
// Basically the only scenario where this'll happen is RGBA masked and DATE is active.
#undef PS_NO_COLOR
#define PS_NO_COLOR 0
#if defined(GL_EXT_shader_framebuffer_fetch)
#undef TARGET_0_QUALIFIER
#define TARGET_0_QUALIFIER inout
#define LAST_FRAG_COLOR SV_Target0
#elif defined(GL_ARM_shader_framebuffer_fetch)
#define LAST_FRAG_COLOR gl_LastFragColorARM
#endif
#endif
#if HAS_DEPTH_FETCH && PS_TEX_IS_DS == 1
#if defined(GL_ARM_shader_framebuffer_fetch_depth_stencil)
#define LAST_FRAG_DEPTH gl_LastFragDepthARM
#endif
#endif
#if !PS_NO_COLOR
#if !defined(DISABLE_DUAL_SOURCE) && !PS_NO_COLOR1
// Same buffer but 2 colors for dual source blending
layout(location = 0, index = 0) TARGET_0_QUALIFIER vec4 SV_Target0;
layout(location = 0, index = 1) out vec4 SV_Target1;
#else
layout(location = 0) TARGET_0_QUALIFIER vec4 SV_Target0;
#endif
#endif
layout(binding = 1) uniform sampler2D PaletteSampler;
#if !HAS_FRAMEBUFFER_FETCH && NEEDS_RT
layout(binding = 2) uniform sampler2D RtSampler; // note 2 already use by the image below
#endif
#if PS_DATE == 3
layout(binding = 3) uniform sampler2D img_prim_min;
// I don't remember why I set this parameter but it is surely useless
//layout(pixel_center_integer) in vec4 gl_FragCoord;
#endif
vec4 fetch_rt()
{
#if !NEEDS_RT
return vec4(0.0);
#elif HAS_FRAMEBUFFER_FETCH
return LAST_FRAG_COLOR;
#else
return texelFetch(RtSampler, ivec2(gl_FragCoord.xy), 0);
#endif
}
vec4 sample_c(vec2 uv)
{
#if PS_TEX_IS_FB == 1
return fetch_rt();
#elif PS_TEX_IS_DS == 1
return vec4(LAST_FRAG_DEPTH, 0.0f, 0.0f, 0.0f);
#else
#if PS_POINT_SAMPLER
// Weird issue with ATI/AMD cards,
// it looks like they add 127/128 of a texel to sampling coordinates
// occasionally causing point sampling to erroneously round up.
// I'm manually adjusting coordinates to the centre of texels here,
// though the centre is just paranoia, the top left corner works fine.
// As of 2018 this issue is still present.
uv = (trunc(uv * WH.zw) + vec2(0.5, 0.5)) / WH.zw;
#endif
uv *= STScale;
#if PS_AUTOMATIC_LOD == 1
return texture(TextureSampler, uv);
#elif PS_MANUAL_LOD == 1
// FIXME add LOD: K - ( LOG2(Q) * (1 << L))
float K = MinMax.x;
float L = MinMax.y;
float bias = MinMax.z;
float max_lod = MinMax.w;
float gs_lod = K - log2(abs(PSin.t_float.w)) * L;
// FIXME max useful ?
//float lod = max(min(gs_lod, max_lod) - bias, 0.0f);
float lod = min(gs_lod, max_lod) - bias;
return textureLod(TextureSampler, uv, lod);
#else
return textureLod(TextureSampler, uv, 0.0f); // No lod
#endif
#endif
}
vec4 sample_p(float idx)
{
return texture(PaletteSampler, vec2(idx, 0.0f));
}
vec4 clamp_wrap_uv(vec4 uv)
{
vec4 uv_out = uv;
#if PS_INVALID_TEX0 == 1
vec4 tex_size = WH.zwzw;
#else
vec4 tex_size = WH.xyxy;
#endif
#if PS_WMS == PS_WMT
#if PS_WMS == 2
uv_out = clamp(uv, MinMax.xyxy, MinMax.zwzw);
#elif PS_WMS == 3
#if PS_FST == 0
// wrap negative uv coords to avoid an off by one error that shifted
// textures. Fixes Xenosaga's hair issue.
uv = fract(uv);
#endif
uv_out = vec4((uvec4(uv * tex_size) & MskFix.xyxy) | MskFix.zwzw) / tex_size;
#endif
#else // PS_WMS != PS_WMT
#if PS_WMS == 2
uv_out.xz = clamp(uv.xz, MinMax.xx, MinMax.zz);
#elif PS_WMS == 3
#if PS_FST == 0
uv.xz = fract(uv.xz);
#endif
uv_out.xz = vec2((uvec2(uv.xz * tex_size.xx) & MskFix.xx) | MskFix.zz) / tex_size.xx;
#endif
#if PS_WMT == 2
uv_out.yw = clamp(uv.yw, MinMax.yy, MinMax.ww);
#elif PS_WMT == 3
#if PS_FST == 0
uv.yw = fract(uv.yw);
#endif
uv_out.yw = vec2((uvec2(uv.yw * tex_size.yy) & MskFix.yy) | MskFix.ww) / tex_size.yy;
#endif
#endif
return uv_out;
}
mat4 sample_4c(vec4 uv)
{
mat4 c;
// Note: texture gather can't be used because of special clamping/wrapping
// Also it doesn't support lod
c[0] = sample_c(uv.xy);
c[1] = sample_c(uv.zy);
c[2] = sample_c(uv.xw);
c[3] = sample_c(uv.zw);
return c;
}
vec4 sample_4_index(vec4 uv)
{
vec4 c;
// Either GS will send a texture that contains a single channel
// in this case the red channel is remapped as alpha channel
//
// Or we have an old RT (ie RGBA8) that contains index (4/8) in the alpha channel
// Note: texture gather can't be used because of special clamping/wrapping
// Also it doesn't support lod
c.x = sample_c(uv.xy).a;
c.y = sample_c(uv.zy).a;
c.z = sample_c(uv.xw).a;
c.w = sample_c(uv.zw).a;
uvec4 i = uvec4(c * 255.0f + 0.5f); // Denormalize value
#if PS_PAL_FMT == 1
// 4HL
return vec4(i & 0xFu) / 255.0f;
#elif PS_PAL_FMT == 2
// 4HH
return vec4(i >> 4u) / 255.0f;
#else
// Most of texture will hit this code so keep normalized float value
// 8 bits
return c;
#endif
}
mat4 sample_4p(vec4 u)
{
mat4 c;
c[0] = sample_p(u.x);
c[1] = sample_p(u.y);
c[2] = sample_p(u.z);
c[3] = sample_p(u.w);
return c;
}
int fetch_raw_depth()
{
#if HAS_CLIP_CONTROL
float multiplier = exp2(32.0f);
#else
float multiplier = exp2(24.0f);
#endif
#if PS_TEX_IS_FB == 1
return int(fetch_rt().r * multiplier);
#elif PS_TEX_IS_DS == 1
return int(LAST_FRAG_DEPTH * multiplier);
#else
return int(texelFetch(TextureSampler, ivec2(gl_FragCoord.xy), 0).r * multiplier);
#endif
}
vec4 fetch_raw_color()
{
#if PS_TEX_IS_FB == 1
return fetch_rt();
#elif PS_TEX_IS_DS == 1
return vec4(LAST_FRAG_DEPTH, 0.0f, 0.0f, 0.0f);
#else
return texelFetch(TextureSampler, ivec2(gl_FragCoord.xy), 0);
#endif
}
vec4 fetch_c(ivec2 uv)
{
#if PS_TEX_IS_DS == 1
return vec4(LAST_FRAG_DEPTH, 0.0f, 0.0f, 0.0f);
#else
return texelFetch(TextureSampler, ivec2(uv), 0);
#endif
}
//////////////////////////////////////////////////////////////////////
// Depth sampling
//////////////////////////////////////////////////////////////////////
ivec2 clamp_wrap_uv_depth(ivec2 uv)
{
ivec2 uv_out = uv;
// Keep the full precision
// It allow to multiply the ScalingFactor before the 1/16 coeff
ivec4 mask = ivec4(MskFix) << 4;
#if PS_WMS == PS_WMT
#if PS_WMS == 2
uv_out = clamp(uv, mask.xy, mask.zw);
#elif PS_WMS == 3
uv_out = (uv & mask.xy) | mask.zw;
#endif
#else // PS_WMS != PS_WMT
#if PS_WMS == 2
uv_out.x = clamp(uv.x, mask.x, mask.z);
#elif PS_WMS == 3
uv_out.x = (uv.x & mask.x) | mask.z;
#endif
#if PS_WMT == 2
uv_out.y = clamp(uv.y, mask.y, mask.w);
#elif PS_WMT == 3
uv_out.y = (uv.y & mask.y) | mask.w;
#endif
#endif
return uv_out;
}
vec4 sample_depth(vec2 st)
{
vec2 uv_f = vec2(clamp_wrap_uv_depth(ivec2(st))) * vec2(float(PS_SCALE_FACTOR)) * vec2(1.0f/16.0f);
ivec2 uv = ivec2(uv_f);
vec4 t = vec4(0.0f);
#if PS_TALES_OF_ABYSS_HLE == 1
// Warning: UV can't be used in channel effect
int depth = fetch_raw_depth();
// Convert msb based on the palette
t = texelFetch(PaletteSampler, ivec2((depth >> 8) & 0xFF, 0), 0) * 255.0f;
#elif PS_URBAN_CHAOS_HLE == 1
// Depth buffer is read as a RGB5A1 texture. The game try to extract the green channel.
// So it will do a first channel trick to extract lsb, value is right-shifted.
// Then a new channel trick to extract msb which will shifted to the left.
// OpenGL uses a FLOAT32 format for the depth so it requires a couple of conversion.
// To be faster both steps (msb&lsb) are done in a single pass.
// Warning: UV can't be used in channel effect
int depth = fetch_raw_depth();
// Convert lsb based on the palette
t = texelFetch(PaletteSampler, ivec2((depth & 0xFF), 0), 0) * 255.0f;
// Msb is easier
float green = float((depth >> 8) & 0xFF) * 36.0f;
green = min(green, 255.0f);
t.g += green;
#elif PS_DEPTH_FMT == 1
// Based on ps_convert_float32_rgba8 of convert
// Convert a GL_FLOAT32 depth texture into a RGBA color texture
#if HAS_CLIP_CONTROL
uint d = uint(fetch_c(uv).r * exp2(32.0f));
#else
uint d = uint(fetch_c(uv).r * exp2(24.0f));
#endif
t = vec4(uvec4((d & 0xFFu), ((d >> 8) & 0xFFu), ((d >> 16) & 0xFFu), (d >> 24)));
#elif PS_DEPTH_FMT == 2
// Based on ps_convert_float16_rgb5a1 of convert
// Convert a GL_FLOAT32 (only 16 lsb) depth into a RGB5A1 color texture
#if HAS_CLIP_CONTROL
uint d = uint(fetch_c(uv).r * exp2(32.0f));
#else
uint d = uint(fetch_c(uv).r * exp2(24.0f));
#endif
t = vec4(uvec4((d & 0x1Fu), ((d >> 5) & 0x1Fu), ((d >> 10) & 0x1Fu), (d >> 15) & 0x01u)) * vec4(8.0f, 8.0f, 8.0f, 128.0f);
#elif PS_DEPTH_FMT == 3
// Convert a RGBA/RGB5A1 color texture into a RGBA/RGB5A1 color texture
t = fetch_c(uv) * 255.0f;
#endif
// warning t ranges from 0 to 255
#if (PS_AEM_FMT == FMT_24)
t.a = ( (PS_AEM == 0) || any(bvec3(t.rgb)) ) ? 255.0f * TA.x : 0.0f;
#elif (PS_AEM_FMT == FMT_16)
t.a = t.a >= 128.0f ? 255.0f * TA.y : ( (PS_AEM == 0) || any(bvec3(t.rgb)) ) ? 255.0f * TA.x : 0.0f;
#endif
return t;
}
//////////////////////////////////////////////////////////////////////
// Fetch a Single Channel
//////////////////////////////////////////////////////////////////////
vec4 fetch_red()
{
#if PS_DEPTH_FMT == 1 || PS_DEPTH_FMT == 2
int depth = (fetch_raw_depth()) & 0xFF;
vec4 rt = vec4(depth) / 255.0f;
#else
vec4 rt = fetch_raw_color();
#endif
return sample_p(rt.r) * 255.0f;
}
vec4 fetch_green()
{
#if PS_DEPTH_FMT == 1 || PS_DEPTH_FMT == 2
int depth = (fetch_raw_depth() >> 8) & 0xFF;
vec4 rt = vec4(depth) / 255.0f;
#else
vec4 rt = fetch_raw_color();
#endif
return sample_p(rt.g) * 255.0f;
}
vec4 fetch_blue()
{
#if PS_DEPTH_FMT == 1 || PS_DEPTH_FMT == 2
int depth = (fetch_raw_depth() >> 16) & 0xFF;
vec4 rt = vec4(depth) / 255.0f;
#else
vec4 rt = fetch_raw_color();
#endif
return sample_p(rt.b) * 255.0f;
}
vec4 fetch_alpha()
{
vec4 rt = fetch_raw_color();
return sample_p(rt.a) * 255.0f;
}
vec4 fetch_rgb()
{
vec4 rt = fetch_raw_color();
vec4 c = vec4(sample_p(rt.r).r, sample_p(rt.g).g, sample_p(rt.b).b, 1.0f);
return c * 255.0f;
}
vec4 fetch_gXbY()
{
#if PS_DEPTH_FMT == 1 || PS_DEPTH_FMT == 2
int depth = fetch_raw_depth();
int bg = (depth >> (8 + ChannelShuffle.w)) & 0xFF;
return vec4(bg);
#else
ivec4 rt = ivec4(fetch_raw_color() * 255.0f);
int green = (rt.g >> ChannelShuffle.w) & ChannelShuffle.z;
int blue = (rt.b << ChannelShuffle.y) & ChannelShuffle.x;
return vec4(green | blue);
#endif
}
//////////////////////////////////////////////////////////////////////
vec4 sample_color(vec2 st)
{
#if (PS_TCOFFSETHACK == 1)
st += TC_OffsetHack.xy;
#endif
vec4 t;
mat4 c;
vec2 dd;
// FIXME I'm not sure this condition is useful (I think code will be optimized)
#if (PS_LTF == 0 && PS_AEM_FMT == FMT_32 && PS_PAL_FMT == 0 && PS_WMS < 2 && PS_WMT < 2)
// No software LTF and pure 32 bits RGBA texure without special texture wrapping
c[0] = sample_c(st);
#ifdef TEX_COORD_DEBUG
c[0].rg = st.xy;
#endif
#else
vec4 uv;
if(PS_LTF != 0)
{
uv = st.xyxy + HalfTexel;
dd = fract(uv.xy * WH.zw);
#if (PS_FST == 0)
// Background in Shin Megami Tensei Lucifers
// I suspect that uv isn't a standard number, so fract is outside of the [0;1] range
// Note: it is free on GPU but let's do it only for float coordinate
dd = clamp(dd, vec2(0.0f), vec2(1.0f));
#endif
}
else
{
uv = st.xyxy;
}
uv = clamp_wrap_uv(uv);
#if PS_PAL_FMT != 0
c = sample_4p(sample_4_index(uv));
#else
c = sample_4c(uv);
#endif
#ifdef TEX_COORD_DEBUG
c[0].rg = uv.xy;
c[1].rg = uv.xy;
c[2].rg = uv.xy;
c[3].rg = uv.xy;
#endif
#endif
// PERF note: using dot product reduces by 1 the number of instruction
// but I'm not sure it is equivalent neither faster.
for (int i = 0; i < 4; i++)
{
//float sum = dot(c[i].rgb, vec3(1.0f));
#if (PS_AEM_FMT == FMT_24)
c[i].a = ( (PS_AEM == 0) || any(bvec3(c[i].rgb)) ) ? TA.x : 0.0f;
//c[i].a = ( (PS_AEM == 0) || (sum > 0.0f) ) ? TA.x : 0.0f;
#elif (PS_AEM_FMT == FMT_16)
c[i].a = c[i].a >= 0.5 ? TA.y : ( (PS_AEM == 0) || any(bvec3(c[i].rgb)) ) ? TA.x : 0.0f;
//c[i].a = c[i].a >= 0.5 ? TA.y : ( (PS_AEM == 0) || (sum > 0.0f) ) ? TA.x : 0.0f;
#endif
}
#if(PS_LTF != 0)
t = mix(mix(c[0], c[1], dd.x), mix(c[2], c[3], dd.x), dd.y);
#else
t = c[0];
#endif
// The 0.05f helps to fix the overbloom of sotc
// I think the issue is related to the rounding of texture coodinate. The linear (from fixed unit)
// interpolation could be slightly below the correct one.
return trunc(t * 255.0f + 0.05f);
}
vec4 tfx(vec4 T, vec4 C)
{
vec4 C_out;
vec4 FxT = trunc(trunc(C) * T / 128.0f);
#if (PS_TFX == 0)
C_out = FxT;
#elif (PS_TFX == 1)
C_out = T;
#elif (PS_TFX == 2)
C_out.rgb = FxT.rgb + C.a;
C_out.a = T.a + C.a;
#elif (PS_TFX == 3)
C_out.rgb = FxT.rgb + C.a;
C_out.a = T.a;
#else
C_out = C;
#endif
#if (PS_TCC == 0)
C_out.a = C.a;
#endif
#if (PS_TFX == 0) || (PS_TFX == 2) || (PS_TFX == 3)
// Clamp only when it is useful
C_out = min(C_out, 255.0f);
#endif
return C_out;
}
void atst(vec4 C)
{
float a = C.a;
#if (PS_ATST == 0)
// nothing to do
#elif (PS_ATST == 1)
if (a > AREF) discard;
#elif (PS_ATST == 2)
if (a < AREF) discard;
#elif (PS_ATST == 3)
if (abs(a - AREF) > 0.5f) discard;
#elif (PS_ATST == 4)
if (abs(a - AREF) < 0.5f) discard;
#endif
}
void fog(inout vec4 C, float f)
{
#if PS_FOG != 0
C.rgb = trunc(mix(FogColor, C.rgb, f));
#endif
}
vec4 ps_color()
{
//FIXME: maybe we can set gl_Position.w = q in VS
#if (PS_FST == 0) && (PS_INVALID_TEX0 == 1)
// Re-normalize coordinate from invalid GS to corrected texture size
vec2 st = (PSin.t_float.xy * WH.xy) / (vec2(PSin.t_float.w) * WH.zw);
vec2 st_int = (PSin.t_int.zw * WH.xy) / (vec2(PSin.t_float.w) * WH.zw);
#elif (PS_FST == 0)
vec2 st = PSin.t_float.xy / vec2(PSin.t_float.w);
vec2 st_int = PSin.t_int.zw / vec2(PSin.t_float.w);
#else
// Note xy are normalized coordinate
vec2 st = PSin.t_int.xy;
vec2 st_int = PSin.t_int.zw;
#endif
#if PS_CHANNEL_FETCH == 1
vec4 T = fetch_red();
#elif PS_CHANNEL_FETCH == 2
vec4 T = fetch_green();
#elif PS_CHANNEL_FETCH == 3
vec4 T = fetch_blue();
#elif PS_CHANNEL_FETCH == 4
vec4 T = fetch_alpha();
#elif PS_CHANNEL_FETCH == 5
vec4 T = fetch_rgb();
#elif PS_CHANNEL_FETCH == 6
vec4 T = fetch_gXbY();
#elif PS_DEPTH_FMT > 0
// Integral coordinate
vec4 T = sample_depth(st_int);
#else
vec4 T = sample_color(st);
#endif
vec4 C = tfx(T, PSin.c);
atst(C);
fog(C, PSin.t_float.z);
return C;
}
void ps_fbmask(inout vec4 C)
{
// FIXME do I need special case for 16 bits
#if PS_FBMASK
vec4 RT = trunc(fetch_rt() * 255.0f + 0.1f);
C = vec4((uvec4(C) & ~FbMask) | (uvec4(RT) & FbMask));
#endif
}
void ps_dither(inout vec3 C)
{
#if PS_DITHER
#if PS_DITHER == 2
ivec2 fpos = ivec2(gl_FragCoord.xy);
#else
ivec2 fpos = ivec2(gl_FragCoord.xy / float(PS_SCALE_FACTOR));
#endif
C += DitherMatrix[fpos.y&3][fpos.x&3];
#endif
}
void ps_color_clamp_wrap(inout vec3 C)
{
// When dithering the bottom 3 bits become meaningless and cause lines in the picture
// so we need to limit the color depth on dithered items
#if SW_BLEND || PS_DITHER || PS_FBMASK
// Correct the Color value based on the output format
#if PS_COLCLIP == 0 && PS_HDR == 0
// Standard Clamp
C = clamp(C, vec3(0.0f), vec3(255.0f));
#endif
// FIXME rouding of negative float?
// compiler uses trunc but it might need floor
// Warning: normally blending equation is mult(A, B) = A * B >> 7. GPU have the full accuracy
// GS: Color = 1, Alpha = 255 => output 1
// GPU: Color = 1/255, Alpha = 255/255 * 255/128 => output 1.9921875
#if PS_DFMT == FMT_16 && PS_BLEND_MIX == 0
// In 16 bits format, only 5 bits of colors are used. It impacts shadows computation of Castlevania
C = vec3(ivec3(C) & ivec3(0xF8));
#elif PS_COLCLIP == 1 || PS_HDR == 1
C = vec3(ivec3(C) & ivec3(0xFF));
#endif
#endif
}
void ps_blend(inout vec4 Color, inout float As)
{
#if SW_BLEND
// PABE
#if PS_PABE
// No blending so early exit
if (As < 1.0f)
return;
#endif
vec3 Cs = Color.rgb;
#if SW_BLEND_NEEDS_RT
vec4 RT = trunc(fetch_rt() * 255.0f + 0.1f);
// FIXME FMT_16 case
// FIXME Ad or Ad * 2?
float Ad = RT.a / 128.0f;
// Let the compiler do its jobs !
vec3 Cd = RT.rgb;
#endif
#if PS_BLEND_A == 0
vec3 A = Cs;
#elif PS_BLEND_A == 1
vec3 A = Cd;
#else
vec3 A = vec3(0.0f);
#endif
#if PS_BLEND_B == 0
vec3 B = Cs;
#elif PS_BLEND_B == 1
vec3 B = Cd;
#else
vec3 B = vec3(0.0f);
#endif
#if PS_BLEND_C == 0
float C = As;
#elif PS_BLEND_C == 1
float C = Ad;
#else
float C = Af;
#endif
#if PS_BLEND_D == 0
vec3 D = Cs;
#elif PS_BLEND_D == 1
vec3 D = Cd;
#else
vec3 D = vec3(0.0f);
#endif
// As/Af clamp alpha for Blend mix
// We shouldn't clamp blend mix with clr1 as we want alpha higher
float C_clamped = C;
#if PS_BLEND_MIX > 0 && PS_CLR_HW != 1
C_clamped = min(C_clamped, 1.0f);
#endif
#if PS_BLEND_A == PS_BLEND_B
Color.rgb = D;
// In blend_mix, HW adds on some alpha factor * dst.
// Truncating here wouldn't quite get the right result because it prevents the <1 bit here from combining with a <1 bit in dst to form a ≥1 amount that pushes over the truncation.
// Instead, apply an offset to convert HW's round to a floor.
// Since alpha is in 1/128 increments, subtracting (0.5 - 0.5/128 == 127/256) would get us what we want if GPUs blended in full precision.
// But they don't. Details here: https://github.com/PCSX2/pcsx2/pull/6809#issuecomment-1211473399
// Based on the scripts at the above link, the ideal choice for Intel GPUs is 126/256, AMD 120/256. Nvidia is a lost cause.
// 124/256 seems like a reasonable compromise, providing the correct answer 99.3% of the time on Intel (vs 99.6% for 126/256), and 97% of the time on AMD (vs 97.4% for 120/256).
#elif PS_BLEND_MIX == 2
Color.rgb = ((A - B) * C_clamped + D) + (124.0f/256.0f);
#elif PS_BLEND_MIX == 1
Color.rgb = ((A - B) * C_clamped + D) - (124.0f/256.0f);
#else
Color.rgb = trunc((A - B) * C + D);
#endif
#if PS_CLR_HW == 1
// Replace Af with As so we can do proper compensation for Alpha.
#if PS_BLEND_C == 2
As = Af;
#endif
// Subtract 1 for alpha to compensate for the changed equation,
// if c.rgb > 255.0f then we further need to adjust alpha accordingly,
// we pick the lowest overflow from all colors because it's the safest,
// we divide by 255 the color because we don't know Cd value,
// changed alpha should only be done for hw blend.
float min_color = min(min(Color.r, Color.g), Color.b);
float alpha_compensate = max(1.0f, min_color / 255.0f);
As -= alpha_compensate;
#elif PS_CLR_HW == 2
// Compensate slightly for Cd*(As + 1) - Cs*As.
// The initial factor we chose is 1 (0.00392)
// as that is the minimum color Cd can be,
// then we multiply by alpha to get the minimum
// blended value it can be.
float color_compensate = 1.0f * (C + 1.0f);
Color.rgb -= vec3(color_compensate);
#endif
#else
// Needed for Cd * (As/Ad/F + 1) blending modes
#if PS_CLR_HW == 1 || PS_CLR_HW == 5
Color.rgb = vec3(255.0f);
#elif PS_CLR_HW == 2 || PS_CLR_HW == 4
// Cd*As,Cd*Ad or Cd*F
#if PS_BLEND_C == 2
float Alpha = Af;
#else
float Alpha = As;
#endif
Color.rgb = max(vec3(0.0f), (Alpha - vec3(1.0f)));
Color.rgb *= vec3(255.0f);
#elif PS_CLR_HW == 3
// Needed for Cs*Ad, Cs*Ad + Cd, Cd - Cs*Ad
// Multiply Color.rgb by (255/128) to compensate for wrong Ad/255 value
Color.rgb *= (255.0f / 128.0f);
#endif
#endif
}
void ps_main()
{
#if PS_SCANMSK & 2
// fail depth test on prohibited lines
if ((int(gl_FragCoord.y) & 1) == (PS_SCANMSK & 1))
discard;
#endif
#if PS_DATE >= 5
#if PS_WRITE_RG == 1
// Pseudo 16 bits access.
float rt_a = fetch_rt().g;
#else
float rt_a = fetch_rt().a;
#endif
#if (PS_DATE & 3) == 1
// DATM == 0: Pixel with alpha equal to 1 will failed
bool bad = (127.5f / 255.0f) < rt_a;
#elif (PS_DATE & 3) == 2
// DATM == 1: Pixel with alpha equal to 0 will failed
bool bad = rt_a < (127.5f / 255.0f);
#endif
if (bad) {
discard;
}
#endif
#if PS_DATE == 3
int stencil_ceil = int(texelFetch(img_prim_min, ivec2(gl_FragCoord.xy), 0).r);
// Note gl_PrimitiveID == stencil_ceil will be the primitive that will update
// the bad alpha value so we must keep it.
if (gl_PrimitiveID > stencil_ceil) {
discard;
}
#endif
vec4 C = ps_color();
#if (APITRACE_DEBUG & 1) == 1
C.r = 255.0f;
#endif
#if (APITRACE_DEBUG & 2) == 2
C.g = 255.0f;
#endif
#if (APITRACE_DEBUG & 4) == 4
C.b = 255.0f;
#endif
#if (APITRACE_DEBUG & 8) == 8
C.a = 128.0f;
#endif
#if PS_SHUFFLE
uvec4 denorm_c = uvec4(C);
uvec2 denorm_TA = uvec2(vec2(TA.xy) * 255.0f + 0.5f);
// Write RB part. Mask will take care of the correct destination
#if PS_READ_BA
C.rb = C.bb;
#else
C.rb = C.rr;
#endif
// FIXME precompute my_TA & 0x80
// Write GA part. Mask will take care of the correct destination
// Note: GLSL 4.50/GL_EXT_shader_integer_mix support a mix instruction to select a component\n"
// However Nvidia emulate it with an if (at least on kepler arch) ...\n"
#if PS_READ_BA
// bit field operation requires GL4 HW. Could be nice to merge it with step/mix below
// uint my_ta = (bool(bitfieldExtract(denorm_c.a, 7, 1))) ? denorm_TA.y : denorm_TA.x;
// denorm_c.a = bitfieldInsert(denorm_c.a, bitfieldExtract(my_ta, 7, 1), 7, 1);
// c.ga = vec2(float(denorm_c.a));
if (bool(denorm_c.a & 0x80u))
C.ga = vec2(float((denorm_c.a & 0x7Fu) | (denorm_TA.y & 0x80u)));
else
C.ga = vec2(float((denorm_c.a & 0x7Fu) | (denorm_TA.x & 0x80u)));
#else
if (bool(denorm_c.g & 0x80u))
C.ga = vec2(float((denorm_c.g & 0x7Fu) | (denorm_TA.y & 0x80u)));
else
C.ga = vec2(float((denorm_c.g & 0x7Fu) | (denorm_TA.x & 0x80u)));
// Nice idea but step/mix requires 4 instructions
// set / trunc / I2F / Mad
//
// float sel = step(128.0f, c.g);
// vec2 c_shuffle = vec2((denorm_c.gg & 0x7Fu) | (denorm_TA & 0x80u));
// c.ga = mix(c_shuffle.xx, c_shuffle.yy, sel);
#endif
#endif
// Must be done before alpha correction
// AA (Fixed one) will output a coverage of 1.0 as alpha
#if PS_FIXED_ONE_A
C.a = 128.0f;
#endif
#if SW_AD_TO_HW
vec4 RT = trunc(fetch_rt() * 255.0f + 0.1f);
float alpha_blend = RT.a / 128.0f;
#else
float alpha_blend = C.a / 128.0f;
#endif
// Correct the ALPHA value based on the output format
#if (PS_DFMT == FMT_16)
float A_one = 128.0f; // alpha output will be 0x80
C.a = (PS_FBA != 0) ? A_one : step(128.0f, C.a) * A_one;
#elif (PS_DFMT == FMT_32) && (PS_FBA != 0)
if(C.a < 128.0f) C.a += 128.0f;
#endif
// Get first primitive that will write a failling alpha value
#if PS_DATE == 1
// DATM == 0
// Pixel with alpha equal to 1 will failed (128-255)
SV_Target0 = (C.a > 127.5f) ? vec4(gl_PrimitiveID) : vec4(0x7FFFFFFF);
return;
#elif PS_DATE == 2
// DATM == 1
// Pixel with alpha equal to 0 will failed (0-127)
SV_Target0 = (C.a < 127.5f) ? vec4(gl_PrimitiveID) : vec4(0x7FFFFFFF);
return;
#endif
ps_blend(C, alpha_blend);
ps_dither(C.rgb);
// Color clamp/wrap needs to be done after sw blending and dithering
ps_color_clamp_wrap(C.rgb);
ps_fbmask(C);
#if !PS_NO_COLOR
#if PS_HDR == 1
SV_Target0 = vec4(C.rgb / 65535.0f, C.a / 255.0f);
#else
SV_Target0 = C / 255.0f;
#endif
#if !defined(DISABLE_DUAL_SOURCE) && !PS_NO_COLOR1
SV_Target1 = vec4(alpha_blend);
#endif
#if PS_NO_ABLEND
// write alpha blend factor into col0
SV_Target0.a = alpha_blend;
#endif
#if PS_ONLY_ALPHA
// rgb isn't used
SV_Target0.rgb = vec3(0.0f);
#endif
#endif
#if PS_ZCLAMP
gl_FragDepth = min(gl_FragCoord.z, MaxDepthPS);
#endif
}
#endif
@@ -0,0 +1,351 @@
#ifndef PS_SCALE_FACTOR
#define PS_SCALE_FACTOR 1.0
#endif
#ifdef VERTEX_SHADER
layout(location = 0) in vec4 a_pos;
layout(location = 1) in vec2 a_tex;
layout(location = 0) out vec2 v_tex;
void main()
{
gl_Position = vec4(a_pos.x, -a_pos.y, a_pos.z, a_pos.w);
v_tex = a_tex;
}
#endif
#ifdef FRAGMENT_SHADER
layout(location = 0) in vec2 v_tex;
#if defined(ps_convert_rgba8_16bits) || defined(ps_convert_float32_32bits)
layout(location = 0) out uint o_col0;
#else
layout(location = 0) out vec4 o_col0;
#endif
layout(set = 0, binding = 0) uniform sampler2D samp0;
vec4 sample_c(vec2 uv)
{
return texture(samp0, uv);
}
#ifdef ps_copy
void ps_copy()
{
o_col0 = sample_c(v_tex);
}
#endif
#ifdef ps_depth_copy
void ps_depth_copy()
{
gl_FragDepth = sample_c(v_tex).r;
}
#endif
#ifdef ps_filter_transparency
void ps_filter_transparency()
{
vec4 c = sample_c(v_tex);
o_col0 = vec4(c.rgb, 1.0);
}
#endif
#ifdef ps_convert_rgba8_16bits
// Need to be careful with precision here, it can break games like Spider-Man 3 and Dogs Life
void ps_convert_rgba8_16bits()
{
uvec4 i = uvec4(sample_c(v_tex) * vec4(255.5f, 255.5f, 255.5f, 255.5f));
o_col0 = ((i.x & 0x00F8u) >> 3) | ((i.y & 0x00F8u) << 2) | ((i.z & 0x00f8u) << 7) | ((i.w & 0x80u) << 8);
}
#endif
#ifdef ps_datm1
void ps_datm1()
{
o_col0 = vec4(0, 0, 0, 0);
if(sample_c(v_tex).a < (127.5f / 255.0f)) // >= 0x80 pass
discard;
}
#endif
#ifdef ps_datm0
void ps_datm0()
{
o_col0 = vec4(0, 0, 0, 0);
if((127.5f / 255.0f) < sample_c(v_tex).a) // < 0x80 pass (== 0x80 should not pass)
discard;
}
#endif
#ifdef ps_hdr_init
void ps_hdr_init()
{
vec4 value = sample_c(v_tex);
o_col0 = vec4(roundEven(value.rgb * 255.0f) / 65535.0f, value.a);
}
#endif
#ifdef ps_hdr_resolve
void ps_hdr_resolve()
{
vec4 value = sample_c(v_tex);
o_col0 = vec4(vec3(uvec3(value.rgb * 65535.5f) & 255u) / 255.0f, value.a);
}
#endif
#ifdef ps_convert_float32_32bits
void ps_convert_float32_32bits()
{
// Convert a vec32 depth texture into a 32 bits UINT texture
o_col0 = uint(exp2(32.0f) * sample_c(v_tex).r);
}
#endif
#ifdef ps_convert_float32_rgba8
void ps_convert_float32_rgba8()
{
// Convert a vec32 depth texture into a RGBA color texture
uint d = uint(sample_c(v_tex).r * exp2(32.0f));
o_col0 = vec4(uvec4((d & 0xFFu), ((d >> 8) & 0xFFu), ((d >> 16) & 0xFFu), (d >> 24))) / vec4(255.0);
}
#endif
#ifdef ps_convert_float16_rgb5a1
void ps_convert_float16_rgb5a1()
{
// Convert a vec32 (only 16 lsb) depth into a RGB5A1 color texture
uint d = uint(sample_c(v_tex).r * exp2(32.0f));
o_col0 = vec4(uvec4((d & 0x1Fu), ((d >> 5) & 0x1Fu), ((d >> 10) & 0x1Fu), (d >> 15) & 0x01u)) / vec4(32.0f, 32.0f, 32.0f, 1.0f);
}
#endif
float rgba8_to_depth32(vec4 unorm)
{
uvec4 c = uvec4(unorm * vec4(255.5f));
return float(c.r | (c.g << 8) | (c.b << 16) | (c.a << 24)) * exp2(-32.0f);
}
float rgba8_to_depth24(vec4 unorm)
{
uvec3 c = uvec3(unorm.rgb * vec3(255.5f));
return float(c.r | (c.g << 8) | (c.b << 16)) * exp2(-32.0f);
}
float rgba8_to_depth16(vec4 unorm)
{
uvec2 c = uvec2(unorm.rg * vec2(255.5f));
return float(c.r | (c.g << 8)) * exp2(-32.0f);
}
float rgb5a1_to_depth16(vec4 unorm)
{
uvec4 c = uvec4(unorm * vec4(255.5f));
return float(((c.r & 0xF8u) >> 3) | ((c.g & 0xF8u) << 2) | ((c.b & 0xF8u) << 7) | ((c.a & 0x80u) << 8)) * exp2(-32.0f);
}
#ifdef ps_convert_rgba8_float32
void ps_convert_rgba8_float32()
{
// Convert an RGBA texture into a float depth texture
gl_FragDepth = rgba8_to_depth32(sample_c(v_tex));
}
#endif
#ifdef ps_convert_rgba8_float24
void ps_convert_rgba8_float24()
{
// Same as above but without the alpha channel (24 bits Z)
// Convert an RGBA texture into a float depth texture
gl_FragDepth = rgba8_to_depth24(sample_c(v_tex));
}
#endif
#ifdef ps_convert_rgba8_float16
void ps_convert_rgba8_float16()
{
// Same as above but without the A/B channels (16 bits Z)
// Convert an RGBA texture into a float depth texture
gl_FragDepth = rgba8_to_depth16(sample_c(v_tex));
}
#endif
#ifdef ps_convert_rgb5a1_float16
void ps_convert_rgb5a1_float16()
{
// Convert an RGB5A1 (saved as RGBA8) color to a 16 bit Z
gl_FragDepth = rgb5a1_to_depth16(sample_c(v_tex));
}
#endif
#define SAMPLE_RGBA_DEPTH_BILN(CONVERT_FN) \
ivec2 dims = textureSize(samp0, 0); \
vec2 top_left_f = v_tex * vec2(dims) - 0.5f; \
ivec2 top_left = ivec2(floor(top_left_f)); \
ivec4 coords = clamp(ivec4(top_left, top_left + 1), ivec4(0), dims.xyxy - 1); \
vec2 mix_vals = fract(top_left_f); \
float depthTL = CONVERT_FN(texelFetch(samp0, coords.xy, 0)); \
float depthTR = CONVERT_FN(texelFetch(samp0, coords.zy, 0)); \
float depthBL = CONVERT_FN(texelFetch(samp0, coords.xw, 0)); \
float depthBR = CONVERT_FN(texelFetch(samp0, coords.zw, 0)); \
gl_FragDepth = mix(mix(depthTL, depthTR, mix_vals.x), mix(depthBL, depthBR, mix_vals.x), mix_vals.y);
#ifdef ps_convert_rgba8_float32_biln
void ps_convert_rgba8_float32_biln()
{
// Convert an RGBA texture into a float depth texture
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth32);
}
#endif
#ifdef ps_convert_rgba8_float24_biln
void ps_convert_rgba8_float24_biln()
{
// Same as above but without the alpha channel (24 bits Z)
// Convert an RGBA texture into a float depth texture
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth24);
}
#endif
#ifdef ps_convert_rgba8_float16_biln
void ps_convert_rgba8_float16_biln()
{
// Same as above but without the A/B channels (16 bits Z)
// Convert an RGBA texture into a float depth texture
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth16);
}
#endif
#ifdef ps_convert_rgb5a1_float16_biln
void ps_convert_rgb5a1_float16_biln()
{
// Convert an RGB5A1 (saved as RGBA8) color to a 16 bit Z
SAMPLE_RGBA_DEPTH_BILN(rgb5a1_to_depth16);
}
#endif
#ifdef ps_convert_rgba_8i
void ps_convert_rgba_8i()
{
// Convert a RGBA texture into a 8 bits packed texture
// Input column: 8x2 RGBA pixels
// 0: 8 RGBA
// 1: 8 RGBA
// Output column: 16x4 Index pixels
// 0: 8 R | 8 B
// 1: 8 R | 8 B
// 2: 8 G | 8 A
// 3: 8 G | 8 A
uvec2 pos = uvec2(gl_FragCoord.xy);
// Collapse separate R G B A areas into their base pixel
uvec2 block = (pos & ~uvec2(15u, 3u)) >> 1;
uvec2 subblock = pos & uvec2(7u, 1u);
uvec2 coord = block | subblock;
// Apply offset to cols 1 and 2
uint is_col23 = pos.y & 4u;
uint is_col13 = pos.y & 2u;
uint is_col12 = is_col23 ^ (is_col13 << 1);
coord.x ^= is_col12; // If cols 1 or 2, flip bit 3 of x
if (floor(PS_SCALE_FACTOR) != PS_SCALE_FACTOR)
coord = uvec2(vec2(coord) * PS_SCALE_FACTOR);
else
coord *= uvec2(PS_SCALE_FACTOR);
vec4 pixel = texelFetch(samp0, ivec2(coord), 0);
vec2 sel0 = (pos.y & 2u) == 0u ? pixel.rb : pixel.ga;
float sel1 = (pos.x & 8u) == 0u ? sel0.x : sel0.y;
o_col0 = vec4(sel1); // Divide by something here?
}
#endif
#ifdef ps_yuv
layout(push_constant) uniform cb10
{
int EMODA;
int EMODC;
};
void ps_yuv()
{
vec4 i = sample_c(v_tex);
vec4 o;
mat3 rgb2yuv;
rgb2yuv[0] = vec3(0.587, -0.311, -0.419);
rgb2yuv[1] = vec3(0.114, 0.500, -0.081);
rgb2yuv[2] = vec3(0.299, -0.169, 0.500);
vec3 yuv = rgb2yuv * i.gbr;
float Y = float(0xDB)/255.0f * yuv.x + float(0x10)/255.0f;
float Cr = float(0xE0)/255.0f * yuv.y + float(0x80)/255.0f;
float Cb = float(0xE0)/255.0f * yuv.z + float(0x80)/255.0f;
switch(EMODA) {
case 0:
o.a = i.a;
break;
case 1:
o.a = Y;
break;
case 2:
o.a = Y/2.0f;
break;
case 3:
o.a = 0.0f;
break;
}
switch(EMODC) {
case 0:
o.rgb = i.rgb;
break;
case 1:
o.rgb = vec3(Y);
break;
case 2:
o.rgb = vec3(Y, Cb, Cr);
break;
case 3:
o.rgb = vec3(i.a);
break;
}
o_col0 = o;
}
#endif
#if defined(ps_stencil_image_init_0) || defined(ps_stencil_image_init_1)
void main()
{
o_col0 = vec4(0x7FFFFFFF);
#ifdef ps_stencil_image_init_0
if((127.5f / 255.0f) < sample_c(v_tex).a) // < 0x80 pass (== 0x80 should not pass)
o_col0 = vec4(-1);
#endif
#ifdef ps_stencil_image_init_1
if(sample_c(v_tex).a < (127.5f / 255.0f)) // >= 0x80 pass
o_col0 = vec4(-1);
#endif
}
#endif
#endif
File diff suppressed because it is too large. Load diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large. Load diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 619 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 620 B

@@ -0,0 +1,56 @@
[
{
"name": "BLOX",
"id": "f82d4c9fdd81518537d88f70c6602bb5",
"uri": "content://com.simongellis.vvb.assets/games/BLOX.vb",
"authors": ["KR155E"]
},
{
"name": "BLOX 2",
"id": "cc91d6389df2c9777919e8e8ab2c0e66",
"uri": "content://com.simongellis.vvb.assets/games/BLOX 2.vb",
"authors": ["KR155E"]
},
{
"name": "Elevated Speed",
"id": "8f7bcfdd0f412d9060b06a97a89fe202",
"uri": "content://com.simongellis.vvb.assets/games/Elevated Speed.vb",
"authors": ["PizzaRollsRoyce"]
},
{
"name": "Fishbone",
"id": "61e38e4e0c43aa8d6274a89ebedd3063",
"uri": "content://com.simongellis.vvb.assets/games/Fishbone.vb",
"authors": ["thunderstruck"]
},
{
"name": "Formula V Public Demo",
"id": "34e9a2ffd60f7ea565caada82d57f29f",
"uri": "content://com.simongellis.vvb.assets/games/Formula V Public Demo.vb",
"authors": ["KR155E"]
},
{
"name": "Red Square",
"id": "9c372321204b9fa65f9324f98aae53ff",
"uri": "content://com.simongellis.vvb.assets/games/Red Square.vb",
"authors": ["Kresna", "Nyrator"]
},
{
"name": "The Red Castle",
"id": "cdb404ff3e1df7b3c13214ac5409d512",
"uri": "content://com.simongellis.vvb.assets/games/The Red Castle.vb",
"authors": ["Timothy Beck"]
},
{
"name": "VUE Snake",
"id": "ccfa400a0ff3d717dad36a3f736fd34d",
"uri": "content://com.simongellis.vvb.assets/games/VUE Snake.vb",
"authors": ["KR155E"]
},
{
"name": "VUEngine Platformer Demo",
"id": "c96d91fb97572a0af7d53f63b292e0f2",
"uri": "content://com.simongellis.vvb.assets/games/VUEngine Platformer Demo.vb",
"authors": ["KR155E"]
}
]
+6 -2
View File
@@ -228,11 +228,15 @@ files:
- name: gamecontrollerdb.txt
required: false
bundled: true
unsourceable: "opened through the asset manager inside the package, so no file on disk reaches this load"
description: "SDL controller mapping database"
note: >-
Read from the assets of the package at startup and handed to SDL as a
memory stream. Nothing outside the archive replaces this copy; an added pad
mapping goes in through controller_map.txt instead.
memory stream. The asset manager reads inside the archive and the path is
a constant, so there is no search order and nothing outside the package
replaces this copy; an added pad mapping goes in through
controller_map.txt instead. The revision shipped here is 589031 bytes and
is not the one other releases carry under this name.
source_ref: "android/app/src/main/cpp/xemu_android.cpp:193-268"
- name: X1_Covers.txt
+110
View File
@@ -0,0 +1,110 @@
emulator: "My Boy!"
type: standalone
core_classification: embedded_hle
source: "https://play.google.com/store/apps/details?id=com.fastemulator.gba"
upstream: closed-source
author: "Pixel Respawn LLC"
profiled_date: "2026-08-12"
core_version: "2.0.3"
display_name: "Nintendo - Game Boy Advance (My Boy!)"
mode: standalone
cores:
- "my-boy"
- "My Boy!"
- "MY-BOY"
systems:
- nintendo-gba
notes: |
Android package com.fastemulator.gba, closed source, sold on Google Play, reached by
ES-DE through its MY-BOY find rule and started with android.intent.action.VIEW on the
content URI of the game. Two Play distribution builds carrying the developer
certificate sha256 942e532dc3a3608a1d04760b8e1b09a2f11c0c8f64ae8bb441f0c8ab1122a7ab
are read here: 2.0.3 (versionCode 90053, minSdk 21, targetSdk 33, arm64-v8a and
armeabi-v7a, bundletool v1 signer and the Play source stamp) and 1.8.0 (versionCode
90048, armeabi and x86). Line numbers below are those of 2.0.3 and native addresses
are arm64-v8a of the same build; 1.8.0 addresses are its x86 library. Four rebuilt
copies were rejected on their certificate: 2.0.9 (CN=APKVISION.ORG), 2.0.8 (C=RU,
O=A1), 2.0.6 (C=IN) and a second 1.8.0 (O=jojoy.mod).
One system is emulated, Game Boy Advance, in libgba.so behind a JNI bridge
(Link.java:21-23,83). Content is a .gba or .bin document, or the first entry with one
of those extensions in a zip document (g.java:71-78,80-100,113-122,
EmulatorActivity.java:2001).
The BIOS is the one file the user supplies. The document picker takes any name from
any location, and the choice is stored as the persisted URI biosUri
(settings/EmulatorSettings.java:65-73,121-135). A document is
accepted only when its reported size is exactly 16384 bytes, or, for an
application/zip document, when an entry declares that size; the name is never
examined (g.java:66-68,80-100,102-111). One that fails leaves the preference reading
"Unrecognized BIOS file." at pick time and on every later visit to the screen
(settings/EmulatorSettings.java:101-108,131-133). At game start the stream is read
until 16384 bytes are in hand and anything shorter raises, which reports "Load BIOS
failed." and passes null (EmulatorActivity.java:1564-1599).
The read happens only while Use BIOS is on, off until the user turns it on; both Boot
BIOS and the file picker depend on that switch, and the advanced reset returns all
three to their defaults (res/xml/settings_advanced.xml,
settings/EmulatorSettings.java:79-80).
The bytes are copied to the head of the emulator's 32 KB BIOS area, offsets 0x2c and
0x39 are cleared, the remainder is zero filled and a flag byte at the end of the area
records that an image is installed (libgba.so 0x165fbc-0x166070, 0x15faf0-0x15fb5c).
With no image that flag is false and the area is filled instead with a 692 byte
replacement inflated from a 488 byte deflate stream in .rodata, byte identical between
1.8.0 and 2.0.3 (0x15ec0c-0x15ec60). Nothing else about the file is examined: no hash
and no content test exists on either side of the bridge.
Two features refuse to mix the two modes. A save state made under the other setting
returns -5 and reports "The save file requires using the BIOS file."
(EmulatorActivity.java:909), and a link connection whose peer disagrees returns 3 and
reports "BIOS settings do not match!" (EmulatorActivity.java:768).
1.8.0 reached the same file through a filesystem path. Its own browser filtered on
.bin, .bios and .zip and wrote the path to biosFile
(settings/EmulatorSettings.java:478-486, FileBrowserActivity.java:196-211), and the
native loader opened it with fopen "rb", or walked it as a zip and took the first
entry, keeping either only when the size callback returned true for exactly 16384
bytes (0x10b680-0x10b76f, 0x10b770-0x10b783, 0x10a1e0-0x10a38d). That build also
looked beside the ROM for a .ips then a .ups image and applied it on load, and wrote
"<name> (patched).gba" from the manual patch entry (Link.java:18,
MainActivity.java:181-208, 0x10b910). Neither the code nor the strings survive in
2.0.3.
Per game settings come from rom_config.ini, an asset of the application keyed on the
four character game code (Console.java:108-130). Shaders are read from the assets of the
separate package com.fastemulator.shaderpack, whose own shaders array names them
(EmulatorActivity.java:1491, settings/EmulatorSettings.java:420,434-438). Battery
saves, states, cheats, screen layouts and key maps are written by the application
under its external files directory (w0/d.java:13-43, Console.java:61-68).
files:
- name: gba_bios.bin
system: nintendo-gba
required: false
hle_fallback: true
has_builtin: true
agnostic: true
size: 16384
validation: [size]
config_key: "useBios"
description: "Game Boy Advance BIOS"
note: >-
Chosen from any location under any name through the document picker, or taken from
the first entry of that size in a zip document. A file of another size is refused
when picked and again when the game starts, and the emulator runs on the
replacement compiled into its library.
source_ref: "My Boy! 2.0.3 g.java:66-68 (size test), g.java:80-100 (zip walk and direct open), settings/EmulatorSettings.java:65-73,121-135 (picker and validation), EmulatorActivity.java:1564-1599 (read and loadBios), libgba.so 0x165fbc-0x166070 (bridge), 0x15faf0-0x15fb5c (install), 0x15ec0c-0x15ec60 (replacement); 1.8.0 settings/EmulatorSettings.java:478-486, libgba.so 0x10b680-0x10b76f, 0x10b770-0x10b783, 0x10a1e0-0x10a38d"
- name: rom_config.ini
system: nintendo-gba
required: false
bundled: true
description: "Per game settings database"
note: >-
Opened from the application assets when a game starts and read as the section
named by its four character code. Save type, flash size, mirroring, sprite limit,
cpu core and the timing hacks become console options, and the addon key arms the
solar, tilt, gyroscope and rumble sensors. Byte identical in 1.8.0 and 2.0.3.
source_ref: "My Boy! 2.0.3 Console.java:108-130, EmulatorActivity.java:642,1132; 1.8.0 Console.java:130-151"
+101
View File
@@ -0,0 +1,101 @@
emulator: "My OldBoy!"
type: standalone
core_classification: embedded_hle
source: "https://play.google.com/store/apps/details?id=com.fastemulator.gbc"
upstream: closed-source
author: "Pixel Respawn LLC"
profiled_date: "2026-08-12"
core_version: "2.0.0"
display_name: "Nintendo - Game Boy / Game Boy Color (My OldBoy!)"
mode: standalone
cores:
- "my-oldboy"
- "My OldBoy!"
- "MY-OLDBOY"
systems:
- nintendo-gb
- nintendo-gbc
- nintendo-sgb
notes: |
Android package com.fastemulator.gbc, closed source, sold on Google Play, reached by
ES-DE through its MY-OLDBOY find rule and started with android.intent.action.VIEW on
the content URI of the game. Two builds carrying the developer certificate sha256
942e532dc3a3608a1d04760b8e1b09a2f11c0c8f64ae8bb441f0c8ab1122a7ab are read here: 2.0.0
(versionCode 90022, minSdk 21, targetSdk 33, arm64-v8a and armeabi-v7a, bundletool v1
signer and the Play source stamp) and 1.5.1 (versionCode 90020, minSdk 9, armeabi,
v1 signature verified entry by entry). Line numbers below are those of 2.0.0 and
native addresses are arm64-v8a of the same build; 1.5.1 addresses are its armeabi
library. 2.0.2 (versionCode 90024) is the current Play build, offered by no mirror
reached here.
Emulation runs in libgbc.so behind a JNI bridge (Link.java:23,29-97). Content is a
.gb, .gbc, .cgb or .dmg document, or the first entry with one of those extensions in a
zip document (g.java:74-81,124-133). A registered .ips or .ups patch is applied to the
loaded image when autoIPS is on (EmulatorActivity.java:2049-2057, Link.patch).
The machine is chosen by consoleType2, one of auto, gbc, gb, gba or sgb
(res/xml/settings_advanced.xml, console_type_entryvalues, EmulatorActivity.java:1168).
The native setter maps those names to 0, 2, 1, 0x12 and 0x21 and then resolves them
against the cartridge header: bit 0x80 of byte 0x143 keeps Game Boy Color, otherwise
byte 0x146 equal to 3 gives Super Game Boy under auto, and everything else falls to
Game Boy (libgbc.so 0x29e74-0x29f30, 0x2436c-0x243bc). Super Game Boy allocates its
own 0x2200 byte state (0x24420-0x24438).
Two boot ROMs are the files the user supplies, one per machine, and the resolved
machine decides which one is installed: type 1 takes the 256 byte image, type 2 takes
the 2304 byte image, both into the same area, and any other type clears the flag that
records an image (libgbc.so 0x2446c-0x2454c). Game Boy Advance and Super Game Boy
modes therefore run without one. The library carries no image of its own, and on reset
the area is passed only when the flag and the reset argument are both set, null
otherwise (0x24550-0x245a8), which is the state the application ships in.
Both files are read only while Boot BIOS is on, off until the user turns it on, and
both pickers declare it as their dependency (res/xml/settings_advanced.xml). A save
state made under the other setting returns -5 and reports "The save file requires
using the BIOS file." (EmulatorActivity.java:898), and a link connection whose peer
disagrees returns 3 and reports "BIOS settings do not match!"
(EmulatorActivity.java:743).
Shaders are read from the assets of the separate package com.fastemulator.shaderpack,
whose own shaders and shader_names arrays name them, with a store link offered when it
is absent (EmulatorActivity.java:1513, settings/EmulatorSettings.java:405,419-423).
Battery saves, real time clock files, states, cheats, screen layouts and key maps are
written by the application under its external files directory (y0/d.java:13-43,
Console.java:58). The only file calls left in the library are those saves, the gzipped
states and one stat on /data/data/com.fastemulator.gbc.
files:
- name: gb_bios.bin
system: nintendo-gb
required: false
hle_fallback: true
agnostic: true
size: 256
validation: [size]
config_key: "bootBios"
description: "Game Boy boot ROM"
note: >-
Chosen from any location under any name through the document picker and kept as
the persisted URI gbBiosUri, or taken from the first entry of that size in a zip
document. A document of another size is refused at pick time with "Invalid GB/GBC
BIOS file." and, if it later reports short, the game starts without it. Installed
only while the resolved machine is Game Boy.
source_ref: "My OldBoy! 2.0.0 EmulatorActivity.java:1170-1175 (gate and 256 byte read), EmulatorActivity.java:1132-1161 (exact length or null), g.java:105-118 (size test), g.java:83-103 (zip walk and direct open), settings/EmulatorSettings.java:84-98,101-120 (picker and validation), libgbc.so 0x2a268-0x2a364 (bridge), 0x2446c-0x2450c (install under type 1), 0x24550-0x245a8 (reset with or without); 1.5.1 settings/EmulatorSettings.java:142-155,229-238, EmulatorActivity.java:683-684, libgbc.so 0x1f7e8-0x1f8c0, 0x10cc0-0x10d3c, 0x10db8 (size 0x100), 0x13180-0x1335c (file or zip entry)"
- name: gbc_bios.bin
system: nintendo-gbc
required: false
hle_fallback: true
agnostic: true
size: 2304
validation: [size]
config_key: "bootBios"
description: "Game Boy Color boot ROM"
note: >-
Chosen from any location under any name through the document picker and kept as
the persisted URI gbcBiosUri, or taken from the first entry of that size in a zip
document. A document of another size is refused at pick time with "Invalid GB/GBC
BIOS file." and, if it later reports short, the game starts without it. Installed
only while the resolved machine is Game Boy Color.
source_ref: "My OldBoy! 2.0.0 EmulatorActivity.java:1170-1175 (gate and 2304 byte read), EmulatorActivity.java:1132-1161 (exact length or null), g.java:105-114,120-122 (size test), g.java:83-103 (zip walk and direct open), settings/EmulatorSettings.java:84-98,101-120 (picker and validation), libgbc.so 0x2a268-0x2a364 (bridge), 0x24510-0x2453c (install under type 2), 0x24550-0x245a8 (reset with or without); 1.5.1 settings/EmulatorSettings.java:142-155,229-238, EmulatorActivity.java:683-684, libgbc.so 0x1f7e8-0x1f8c0, 0x10d40-0x10d7c, 0x10dc8 (size 0x900), 0x13180-0x1335c (file or zip entry)"
+168
View File
@@ -0,0 +1,168 @@
emulator: "NES.emu"
type: standalone
core_classification: community_fork
source: "https://github.com/Rakashazi/emu-ex-plus-alpha"
upstream: "https://github.com/TASEmulators/fceux"
profiled_date: "2026-08-12"
source_commit: "1c12fac5ce49badaadff2e2f210dcc30b89f4943"
upstream_commit: "d339f1fa0cd8b69cc637a0de3fb3f04cb28748ea"
core_version: "1.5.85"
display_name: "Nintendo - NES / Famicom (NES.emu)"
mode: standalone
cores:
- "nes-emu"
- "NES.emu"
- "NES-EMU"
systems:
- nintendo-nes
- nintendo-fds
notes: |
Member of the EX Emulator series by Robert Broglia, which targets Android and
Linux (README.md:1,3-4,12-13) and keeps iOS and Pandora build shortcuts in the
tree (NES.emu/ios.mk, NES.emu/pandora.mk). Published as com.explusalpha.NesEmu
(NES.emu/metadata/conf.mk:2,4,6,7) and reached by ES-DE through its NES-EMU
find rule, which only the Android rule set carries. FCEUX 2.7.0 is vendored
under NES.emu/src/fceu (NES.emu/src/fceu/version.h:63-65,
NES.emu/src/main/AppMeta.cc:26), synced at FCEUX git d339f1f of 2025.11.11 per
the app changelog, and driven by the app's own video, audio, input
and save layers. The Qt and Windows drivers, netplay, PNG snapshots, WAV
logging and FCEUX's own config parser are left out of the build
(NES.emu/src/CMakeLists.txt:8-62), and the file name types for movies,
snapshots and on-disk states return an empty string
(NES.emu/src/main/FceuApi.cc:367-379). Content is read from
.nes, .unf, .unif, .fds and .nsf files (NES.emu/metadata/conf.mk:5,
NES.emu/src/main/system.ccm:108-118, NES.emu/src/main/AppMeta.cc:34); an
archive is opened by the framework, which keeps the first entry passing that
same filter (EmuFramework/src/EmuSystem.cc:394-412).
The Disk System BIOS is the one file the user has to supply, and only for .fds
content. Its location is an option rather than a fixed name
(NES.emu/src/main/system.ccm:64,143, NES.emu/src/main/options.cc:64-65,112),
set through a selector that accepts a name ending .rom or .bin caselessly, or
an archive holding such an entry (NES.emu/src/main/EmuMenuViews.cc:609-624,
NES.emu/src/main/system.ccm:107, NES.emu/src/main/FceuApi.cc:233-254). The
image must measure exactly 8192 bytes; a shorter or longer one is refused as
"Incompatible FDS BIOS" and an unset path as "No FDS BIOS set"
(NES.emu/src/main/FceuApi.cc:227-231,244-248,257-263). Either answer makes the
loader free the disk data and return an error, so the content never runs
(NES.emu/src/fceu/fds.cpp:915-926, NES.emu/src/main/Main.cc:317-322). The
bytes are mapped as PRG bank 0 and are never hashed
(NES.emu/src/fceu/fds.cpp:916-917).
The Default Palette option selects FCEUX's built-in table, one of six palettes
read from the palette directory of the application bundle, or a .pal file the
user picks (NES.emu/src/main/EmuMenuViews.cc:311-315,318,336-361,
NES.emu/src/main/Main.cc:149-175, NES.emu/src/main/options.cc:30). The loader
reads up to 512 three byte entries, skips a file carrying fewer than 64 colors
and generates the deemphasis rows for any count other than 512
(NES.emu/src/main/Main.cc:134-147). Two further palette names are declared and
never wired to a menu item or shipped as assets
(NES.emu/src/main/EmuMenuViews.cc:316-317). A .pal named after the content in
the palettes directory overrides the default at load time
(NES.emu/src/main/FceuApi.cc:365-366, NES.emu/src/fceu/fceu.cpp:522,
NES.emu/src/fceu/palette.cpp:318-338).
FCEU_MakeFName maps the Game Genie ROM to gg.rom beside the content
(NES.emu/src/main/FceuApi.cc:361-362), but the only site that opens it sits
behind FSettings.GameGenie (NES.emu/src/fceu/cart.cpp:351-368,
NES.emu/src/fceu/fceu.cpp:509-511). FCEUI_Initialize clears that structure
(NES.emu/src/fceu/fceu.cpp:601,613) and nothing sets the flag: the app declares
no option for it (NES.emu/src/main/system.ccm:62-76,
NES.emu/src/main/options.cc:58-142) and the single call site of
FCEUI_SetGameGenie passes false (NES.emu/src/fceu/fceu.cpp:513,1218-1219). The
file is never read.
Per content the app writes and reads back files named after the ROM: a .sav for
cartridges wired to a battery (NES.emu/src/fceu/cart.cpp:536-586,
NES.emu/src/main/Main.cc:98-120), a .fds.sav holding the modified disk
(NES.emu/src/fceu/fds.cpp:1011-1040), .fcs states
(NES.emu/src/main/Main.cc:78-96), a .cht cheat list under the cheats path
(NES.emu/src/fceu/cheat.cpp:200-227,324-343, NES.emu/src/main/Cheats.cc:42-50)
and NesEmu.config (NES.emu/src/main/AppMeta.cc:27). An .ips named after the
content in the patches path is applied to the image as it loads
(NES.emu/src/main/Main.cc:312-316). The app declares no bundled content, the
framework definition defaulting to an empty span
(EmuFramework/src/AppMeta.cc:40,
EmuFramework/include/emuframework/AppMeta.hh:66-68).
files:
- name: "disksys.rom"
system: nintendo-fds
required: true
size: 8192
validation: [size]
description: "Famicom Disk System BIOS"
note: >-
Read through a path the user sets, so no name is compiled in; the selector
accepts any name ending .rom or .bin caselessly, or an archive whose first
entry with one of those extensions is used. The size must be exactly 8192
bytes, and a mismatch or an unset path ends the load of any .fds content.
The image is never hashed.
source_ref: "NES.emu/src/main/FceuApi.cc:221-265, NES.emu/src/fceu/fds.cpp:915-926, NES.emu/src/main/EmuMenuViews.cc:609-624, NES.emu/src/main/system.ccm:107"
- name: "Digital Prime (FBX).pal"
path: "palette/Digital Prime (FBX).pal"
system: nintendo-nes
required: false
bundled: true
category: game_data
size: 192
sha1: "e37da23fa2c644a40fb6c08dd885a96fd65bf4e5"
description: "Default Palette option, 64 colors"
source_ref: "NES.emu/src/main/EmuMenuViews.cc:311,339, NES.emu/src/main/Main.cc:134-147,159-163"
- name: "Smooth V2 (FBX).pal"
path: "palette/Smooth V2 (FBX).pal"
system: nintendo-nes
required: false
bundled: true
category: game_data
size: 192
sha1: "1e1993f917ec098268a0af15e79b1002bf425e47"
description: "Default Palette option, 64 colors"
source_ref: "NES.emu/src/main/EmuMenuViews.cc:312,340, NES.emu/src/main/Main.cc:134-147,159-163"
- name: "Magnum (FBX).pal"
path: "palette/Magnum (FBX).pal"
system: nintendo-nes
required: false
bundled: true
category: game_data
size: 192
sha1: "04d7490bb3a284ab266a555c02526f6743756661"
description: "Default Palette option, 64 colors"
source_ref: "NES.emu/src/main/EmuMenuViews.cc:313,341, NES.emu/src/main/Main.cc:134-147,159-163"
- name: "Classic (FBX).pal"
path: "palette/Classic (FBX).pal"
system: nintendo-nes
required: false
bundled: true
category: game_data
size: 192
sha1: "37027d92e1015b82a7dc5c43e9f1649a961577ab"
description: "Default Palette option, 64 colors"
source_ref: "NES.emu/src/main/EmuMenuViews.cc:314,342, NES.emu/src/main/Main.cc:134-147,159-163"
- name: "Wavebeam.pal"
path: "palette/Wavebeam.pal"
system: nintendo-nes
required: false
bundled: true
category: game_data
size: 192
sha1: "a33356beefeb0b110464e7d77b3238fc1fb90230"
description: "Default Palette option, 64 colors"
source_ref: "NES.emu/src/main/EmuMenuViews.cc:315,343, NES.emu/src/main/Main.cc:134-147,159-163"
- name: "Five Reality.pal"
path: "palette/Five Reality.pal"
system: nintendo-nes
required: false
bundled: true
category: game_data
size: 192
sha1: "5008c37920c614e8b471b45ac23118d00162b804"
description: "Default Palette option, 64 colors"
source_ref: "NES.emu/src/main/EmuMenuViews.cc:318,344, NES.emu/src/main/Main.cc:134-147,159-163"
+184
View File
@@ -0,0 +1,184 @@
emulator: Nesoid
type: standalone
core_classification: community_fork
source: "https://github.com/proninyaroslav/nesoid"
upstream: "https://sourceforge.net/p/nesoid/code"
author: "Yongzh (androidemu.com)"
profiled_date: "2026-08-12"
source_commit: "b2ff53fefa56a668aad4a579af85adc672d7a791"
core_version: "2.5"
display_name: "Nintendo - NES / Famicom (Nesoid)"
mode: standalone
cores:
- "nesoid"
- "Nesoid"
- "NESOID"
systems:
- nintendo-nes
- nintendo-fds
notes: |
Android package com.androidemu.nes, launched on the path of the content with
android.intent.action.VIEW; the activity declares the file scheme with the
application/zip and application/octet-stream types
(app/src/main/AndroidManifest.xml:59-71). Two build families answer to that
package id. Yongzh's own closed builds come first, and 2.3 (versionCode 56)
and 2.5.0 (versionCode 62) are read here, both carrying his certificate sha256
744b1df1b3610d58e447d243521a0957cc5f4ebd50b12d2816a92396d1aa32f2 (C=CN,
O=androidemu.com, freeman.yong@gmail.com). He later published the sources; the
SourceForge project carried them on and Yaroslav Pronin forked that tree to
GitHub, where release 2.5-4 (versionName 2.5, versionCode 61, armeabi-v7a,
certificate O=Free Software CN=Yaroslav Pronin) is the build ES-DE names. The
SourceForge community rebuild of the same tree (com.androidemu.nes_61.apk,
certificate O=Alcatraz CN=Birdman) was read beside it. Line numbers are the
fork's, native addresses are the armeabi library of Yongzh's 2.5.0, and the
SourceForge tree carries general.c and fds.c byte identical to the fork.
The emulation core is neslib, FCE Ultra 0.98 reached through the GP2X port
GPFCE, whose driver and blitters still sit in the tree unbuilt
(app/jni/neslib/drivers/gp2x/, giz_blit.s). The Android build compiles the
mapper, board and input sets with its own four file driver
(app/jni/neslib/Android.mk:12-197), leaves netplay out of the library and
runs it from Java instead (app/jni/neslib/fce.c:1081,1206,
app/jni/neslib/drivers/android/netplay.c:1,28), and reduces
FCEUD_PrintError and FCEUD_Message to empty bodies, so every message the core
raises is discarded (app/jni/neslib/drivers/android/debug.c:4-11).
The activity accepts a name ending .nes, .fds or .zip caselessly and refuses
anything else before the loader runs (EmulatorActivity.java:933-957,
app/src/main/res/values/arrays.xml:4-8). An archive is opened by the core,
which keeps the first entry ending .nes, .fds, .nsf, .unf, .nez or .unif, and
a plain file also opens gzipped (app/jni/neslib/file.c:192-232,250-273).
FCEUI_LoadGame then tries the iNES, NSF, FDS and UNIF loaders in that order on
the bytes themselves (app/jni/neslib/fce.c:1180-1187).
The Disk System BIOS is the file the user has to supply. FDSLoad asks
FCEU_MakeFName for it, opens it with a plain fopen and reads 8192 bytes into
the array mapped over 0xE000 to 0xFFFF (app/jni/neslib/fds.c:76,146,160,
808-843, app/jni/neslib/drivers/android/file.c:3-6). Where that name resolves
is the one place the two build families differ. Yongzh's builds carry a
setOption entry fdsRom that duplicates the path the settings screen holds and
return it from FCEU_MakeFName when set (libnes.so setOption 0x455a4-0x45694,
setter 0x8804-0x8848, FCEUMKF_FDSROM case 0x8094-0x80ac,
Nesoid 2.5.0 EmulatorActivity.java:834). The published sources carry neither
the option nor that branch, so only the fallback remains: FCEUMKF_FDSROM
formats disksys.rom under the base directory, and nothing on Android ever
calls FCEUI_SetBaseDirectory, which leaves that buffer empty
(app/jni/neslib/general.c:46,52-56,215). The settings screen still writes the
fdsRom preference and still shows the chosen path, but no code reads it back
(EmulatorSettingsFragment.java:96-99,150-156,195-210,
app/src/main/res/xml/preferences.xml:240-251). Disk switching went the same
way: the menu asks the engine for fdsTotalSides and fdsCurrentDisk, which
Yongzh's builds answer and the fork's does not, the base class returning zero
for any name (EmulatorActivity.java:417,969,1244-1249,
app/jni/common/emuengine.h:49).
The Game Genie ROM is a second path the user picks, kept across both families.
loadGameGenie passes it to the engine only while the Enable Game Genie switch
is on, the setter duplicates it into FSettings.GameGenie and OpenGenie reads it
once the content has loaded (EmulatorActivity.java:870-874,
app/jni/neslib/drivers/android/nesengine.cpp:242-243,
app/jni/neslib/svga.c:132-140, app/jni/neslib/fce.c:1201-1203). Both pickers
list names ending .nes, .rom or .bin
(EmulatorSettingsFragment.java:179-210, FileChooser.java:157-172).
A palette named after the content is read from the pal directory of the same
unset base directory as the disk BIOS, 192 bytes taken as 64 RGB triples; a
missing file leaves the built-in table in place
(app/jni/neslib/palette.c:205-224, app/jni/neslib/general.c:216-221,
app/jni/neslib/fce.c:1212).
Per content the emulator writes and reads back its own files, all under that
same base directory: sav/<name>.sav for battery backed cartridge RAM
(app/jni/neslib/cart.c:641-700), sav/<name>.fds for the modified disk
(app/jni/neslib/fds.c:845-870,915-930), fcs/<name>.fc<n> states,
snaps/ screenshots and movie/<name>.fcm recordings
(app/jni/neslib/general.c:134-195,222-238), and cheats/<name>.cht, which
FCEU_LoadGameCheats reads at load and FCEU_FlushGameCheats rewrites at close
(app/jni/neslib/cheat.c:183-208,272-300, app/jni/neslib/fce.c:1080,1213).
The application writes its own files through Java paths instead: state slots
at <content>.ss<n> beside the content (StateSlotsActivity.java:39-45,135-140),
an XML cheat list at <content>.cht, also beside the content
(Cheats.java:37-46,105-160), key profiles under its data directory
(KeyProfilesActivity.java:47-60,92-100), PNG screenshots under screenshot/ on
external storage (EmulatorActivity.java:1258-1281) and a netplay state
exchanged through its cache directory (EmulatorActivity.java:1292-1293).
files:
- name: disksys.rom
system: nintendo-fds
required: true
min_size: 8192
validation: [size]
config_key: "fdsRom"
description: "Famicom Disk System BIOS"
note: >-
Read as 8192 bytes into the 8 KB array mapped over 0xE000 to 0xFFFF. A
failed open or a short read frees the disk data and ends the load, so no
.fds content runs; both messages are discarded and the application reports
only that the ROM failed to load. Nothing else about the image is
examined, so a longer file passes on its first 8192 bytes and no hash is
compared. The open is a plain fopen, so neither a zipped nor a gzipped
copy answers. Yongzh's builds take the path from the fdsRom setting, whose
picker lists names ending .nes, .rom or .bin; the builds made from the
published sources ignore that setting and resolve the compiled name under
a base directory that is never set, which puts it at the root of the
filesystem.
source_ref: "app/jni/neslib/fds.c:808-843 (open, read, failure), app/jni/neslib/fds.c:76,146,160 (array and mapping), app/jni/neslib/general.c:46,52-56,215 (name and empty base directory), app/jni/neslib/drivers/android/file.c:3-6 (plain fopen); Nesoid 2.5.0 libnes.so 0x455a4-0x45694 (setOption fdsRom), 0x8804-0x8848 (setter), 0x8094-0x80ac (FCEUMKF_FDSROM returns the set path), Nesoid 2.5.0 EmulatorActivity.java:834"
- name: gg.rom
system: nintendo-nes
required: false
min_size: 4352
validation: [size]
config_key: "gameGenieRom"
description: "Game Genie add-on cartridge ROM"
note: >-
Read only while the Enable Game Genie switch is on and a path is set,
through a picker listing names ending .nes, .rom or .bin. The first 16
bytes decide the format: a leading 0x4E is taken as an iNES image, from
which 4096 bytes of program ROM are read, then 256 bytes of character ROM
16 KB further in, so such a file needs at least 16656 bytes; anything else
is read as a raw 4352 byte image. A failed open or a short read leaves the
Game Genie off and the content still runs. No hash is compared.
source_ref: "app/jni/neslib/cart.c:475-521 (open and format branch), app/jni/neslib/svga.c:132-140 (setter), app/jni/neslib/drivers/android/nesengine.cpp:242-243, app/jni/neslib/fce.c:1201-1203 (call site), EmulatorActivity.java:870-874, EmulatorSettingsFragment.java:179-193 (picker)"
- name: "<game>.pal"
system: nintendo-nes
required: false
category: game_data
unsourceable: "any 64 colour palette the user picks for one title"
description: "colour palette for one title"
note: >-
Opened as pal/<name>.pal under the base directory when content loads, with
the name taken from the content. 192 bytes are read as 64 RGB triples and
replace the built-in table, without checking how many arrived, so a
shorter file leaves the remaining entries unset; a missing file changes
nothing. The base directory is never set on Android, so the name resolves
at the root of the filesystem.
source_ref: "app/jni/neslib/palette.c:205-224, app/jni/neslib/general.c:216-221, app/jni/neslib/fce.c:1212"
exclusion_note: >
Left out are the files the emulator writes and reads back, which are its own
state rather than anything a user obtains: sav/<name>.sav for battery backed
cartridge RAM, sav/<name>.fds for the modified disk, fcs/<name>.fc<n> states,
snaps/ screenshots, movie/<name>.fcm recordings and cheats/<name>.cht, which
is reread at load and rewritten at close. The application writes its own set
through Java paths: state slots at <content>.ss<n>, an XML cheat list at
<content>.cht beside the content, key profiles, PNG screenshots under
screenshot/ and the netplay state in its cache directory. The IPS branch is
unreachable: FCEUMKF_IPS has no call site, and the only patcher applies a .ips
handed in as the content itself, which the activity refuses before the loader
runs. The netplay temporary file
goes with the netplay code, which the Android build does not compile. The
gg.rom name FCEU_MakeFName builds is never opened, the Game Genie image
arriving as a path instead. assets/about.html and assets/faq.html are the help
screens of the application and carry no emulation data.
ref: app/jni/neslib/general.c:196-213,222-238, app/jni/neslib/cart.c:641-700,
app/jni/neslib/fds.c:845-870,915-930, app/jni/neslib/cheat.c:183-208,
272-300, app/jni/neslib/fce.c:1080,1145-1177,1206,1213,
EmulatorActivity.java:949-957,1258-1293, Cheats.java:37-46,
StateSlotsActivity.java:39-45,135-140,
KeyProfilesActivity.java:47-60,92-100, app/jni/neslib/Android.mk:193-197,
HelpActivity.java:14-22, MainActivity.java:20,
EmulatorSettingsFragment.java:30-31
+823
View File
@@ -0,0 +1,823 @@
emulator: NetherSX2-Turnip Classic
type: standalone
core_classification: community_fork
bios_mode: agnostic
source: "https://github.com/nckstwrt/NetherSX2-Turnip"
upstream: "https://github.com/Trixarian/AetherSX2"
author: "nckstwrt"
profiled_date: "2026-08-12"
source_commit: "8e17e584884e19b0a912f1988730d576d6d5aa84"
upstream_commit: "1d1f795dfc70e38da67724c7298779260f513889"
core_version: "2.2n-3668-Turnip-v0.7"
display_name: "Sony - PlayStation 2 (NetherSX2-Turnip Classic)"
mode: standalone
cores:
- "nethersx2-turnip-classic"
- "NetherSX2-Turnip-Classic"
- "NETHERSX2-TURNIP-CLASSIC"
systems:
- sony-playstation-2
bios_directory: "bios/"
notes: |
PlayStation 2 emulator for Android, package xyz.aethersx2.cturnip, activity
xyz.aethersx2.android.EmulationActivity, version name v2.2n-3668, label
NetherSX2 Classic (Turnip). It sits on the 3668 line: the library it starts
from is NetherSX2 Classic v2.2n-3668, itself a patch of the AetherSX2
v1.5-3668 package, and the library still names itself NetherSX2 v2.2n-3668
(Classic). Everything below was read from the v0.7 package:
lib/arm64-v8a/libemucore.so, libvulkad.so, the dex and the assets.
ref: nethersx2-turnip-classic v0.7 AndroidManifest.xml,
nethersx2-turnip-classic v0.7 libemucore.so 0xcdcba
The package pairs two revisions of the project. libemucore.so is the blob the
v0.7 commit carries, byte for byte; libvulkad.so is the one committed for
v0.6 and reports its own build date. libhook_impl.so, libmain_hook.so and the
six packed drivers are the same at both revisions. The shim rules described
here are therefore those of the older revision, which this profile pins:
SM8350, lahaina, sdm845 and napali still route to the a6xx-Patched driver,
and SM6475, SM6650 and SM7325 are not known to it.
ref: VulkanShim2/vulkan_shim.cpp:1027-1059,
nethersx2-turnip-classic v0.7 libvulkad.so
The patch rewrites twenty-four places in the library it starts from. Three are
the strings libvulkan.so, libvulkan.so.1 and the message naming them, each
turned into libvulkad.so, so the Vulkan loader opens the shim instead of the
system driver. Sixteen turn comparisons into unconditional paths, among them
the memchr scan for the twenty-two byte pattern that precedes the certificate
test and two byte-wise string comparisons whose result is forced to equal,
which is what lets the package be resigned under a new application id. Five
move settings defaults: the renderer enum from 12 to 14, the upscale
multiplier fallback from 1.0 to 2.0 with the configuration read
short-circuited, the hardware download mode default, and the warning text that
went with it. The same five sites carry their unpatched forms in the 4248
library this project also starts from, which is what places them here rather
than in the base. None of them is in a file loading path.
ref: nethersx2-turnip-classic v0.7 libemucore.so 0x105f5b,
nethersx2-turnip-classic v0.7 libemucore.so 0x829ae0-0x82a018,
nethersx2-turnip-classic v0.7 libemucore.so 0x82d10c-0x82d5c0,
nethersx2-turnip-classic v0.7 libemucore.so 0x82e41c,
nethersx2-turnip-classic v0.7 libemucore.so 0x82fbac-0x82fcac,
nethersx2-turnip-classic v0.7 libemucore.so 0x8034c4,
nethersx2-turnip-classic v0.7 libemucore.so 0x833d04,
nethersx2-turnip-classic v0.7 libemucore.so 0x83401c-0x834028,
nethersx2-turnip-classic v0.7 libemucore.so 0x834cb0
A BIOS image is required and boot stops without one, the application raising a
startup error saying it needs a PS2 BIOS in the bios folder of the data
directory. The data directory is getExternalFilesDir(null) with getDataDir()
behind it, so it follows the application id, and the folder names under it
come from the Folders section, Bios defaulting to bios. An image imported
through the interface is written to that folder under the CRC32 of its
contents, as %08X.bin.
ref: nethersx2-turnip-classic v0.7 libemucore.so 0x8057dc,
nethersx2-turnip-classic v0.7 libemucore.so 0x7dfaf0-0x7dfb10,
xyz/aethersx2/android/NativeLibrary initializeOnce,
xyz/aethersx2/android/NativeLibrary importBIOS
Detection is by content. The scan lists the BIOS folder with a * mask, keeps
files between 4194304 and 8388608 bytes, and accepts an image whose romdir
carries a RESET entry followed by a readable ROMVER; the fifth ROMVER
character gives the zone, A for USA, C for China, E for Europe, H for Asia,
J for Japan, P for Free, T for T10K and X for Test, any other character
standing for itself. The sixth character is read only to pick the word
Console or Devel for the description, and the acceptance flag is set outright
once ROMVER has been read, so development images pass with nothing patched
here. RESET and ROMVER are the only two names the scan compares. An image
named in the configuration is combined with the BIOS folder and opened at that
path when it exists, without the size filter and without the romdir test. No
name and no hash is matched anywhere. The image is read into the 4 MB ROM
region and truncated to it, and one shorter than 2465792 bytes turns off the
OSDSys parameter HLE.
ref: aethersx2/pcsx2/ps2/BiosTools.cpp:27-28,
aethersx2/pcsx2/ps2/BiosTools.cpp:62-175,
aethersx2/pcsx2/ps2/BiosTools.cpp:235-260,
aethersx2/pcsx2/ps2/BiosTools.cpp:272-332,
nethersx2-turnip-classic v0.7 libemucore.so 0x81bc00-0x81bc24,
nethersx2-turnip-classic v0.7 libemucore.so 0x81be44-0x81c1c0,
nethersx2-turnip-classic v0.7 libemucore.so 0x81b5e8-0x81b62c
Companions derive from the selected image. rom1 and rom2 are appended to the
full name first, then substituted for the existing extension, so an image at
ps2-0230a-20080220.bin is followed by ps2-0230a-20080220.bin.rom1 then
ps2-0230a-20080220.rom1. The nvm and the mec are read at the substituted
extension only, and both are written with defaults when they are absent or too
short. This code line loads no erom: the extension is named nowhere in the
library and the boot path goes from rom2 straight to the IRX.
ref: aethersx2/pcsx2/ps2/BiosTools.cpp:193-218,
aethersx2/pcsx2/CDVD/CDVD.cpp:120-144,
aethersx2/pcsx2/CDVD/CDVD.cpp:158-226,
nethersx2-turnip-classic v0.7 libemucore.so 0x81b688-0x81b9a4
The network adapter opens eeprom.dat and flash.dat by bare name, so they
resolve against the process working directory, which the application never
sets. A compiled-in image stands in for the first and a card filled with 0xFF
for the second. DEV9hdd.raw is the default name of the empty disk image its
settings page writes. An IRX named in the configuration is read into the ROM
region at 0x3C0000 at boot; the field is empty by default and names no file of
its own.
ref: aethersx2/pcsx2/DEV9/DEV9.cpp:73, aethersx2/pcsx2/DEV9/DEV9.cpp:145-160,
aethersx2/pcsx2/DEV9/flash.cpp:76-103,
aethersx2/pcsx2/ps2/BiosTools.cpp:220-233,
nethersx2-turnip-classic v0.7 libemucore.so 0x7bb5cc-0x7bb680,
nethersx2-turnip-classic v0.7 libemucore.so 0x81b9a4-0x81bac4
The Vulkan path is the reason this build exists. libemucore.so opens
libvulkad.so.1 then libvulkad.so where the stock library names libvulkan.so,
and vkCreateInstance is resolved from it. That shim reads the Adreno model and
the platform name from the kgsl sysfs nodes, picks one of six Turnip drivers
packed beside it, creates a linker namespace over its own library directory
and loads libhook_impl.so and libmain_hook.so into it. The system
/system/lib64/libvulkan.so is then opened inside that namespace with its
soname patched, so its own driver load lands in the hook, which opens the
chosen Turnip driver instead of the vendor ICD. A driver present at
/data/local/tmp/libvulkan_freedreno.so is tested first and wins over all six.
When the namespace cannot be built the shim falls back to patching the system
library's global offset table, and that path alone loads libbase.so,
libcutils.so, libvndksupport.so and libhardware.so from the library directory.
The shim derives the package name from its own library path and appends to
vulkan_shim.log under the files folder of that package.
ref: VulkanShim2/vulkan_shim.cpp:43-73,
VulkanShim2/vulkan_shim.cpp:1008-1085,
VulkanShim2/vulkan_shim.cpp:1107-1175,
VulkanShim2/vulkan_shim.cpp:1179-1194,
VulkanShim2/hook_impl.cpp:38-140,
nethersx2-turnip-classic v0.7 libemucore.so 0x8a45ec-0x8a4624
Resources are read out of the package itself. The library has no asset manager
of its own and calls back into readPackageFile, readPackageFileToString and
playSoundAsync, each taking an asset-relative name, so the game database, the
patch archives, the interface fonts, the shader sources every backend compiles
at startup and the achievement sounds are versioned with the build and never
looked for on disk. The sound names are joined to a file:///android_asset base
before they cross into Java. The game list draws its region flags and rating
stars from the same assets. The game database is this build's own, and five of
the shader sources differ from the ones the 4248 line carries: the OpenGL
preamble, its format conversion and texture function fragment shaders, and the
Vulkan texture function and format conversion shaders.
ref: nethersx2-turnip-classic v0.7 libemucore.so 0x828110,
xyz/aethersx2/android/NativeLibrary readPackageFile,
xyz/aethersx2/android/NativeLibrary playSoundAsync
files:
- name: ps2-0230a-20080220.bin
path: bios/ps2-0230a-20080220.bin
required: true
min_size: 4194304
max_size: 8388608
validation: [size]
description: "PS2 BIOS image"
note: >-
Any image whose romdir holds RESET and a readable ROMVER is accepted,
whatever its name. The 4 to 8 MB range gates the folder scan; an image
named in the configuration skips both that range and the romdir test.
source_ref: "aethersx2/pcsx2/ps2/BiosTools.cpp:27-28, aethersx2/pcsx2/ps2/BiosTools.cpp:235-260, nethersx2-turnip-classic v0.7 libemucore.so 0x81bc00-0x81bc24 (size window), nethersx2-turnip-classic v0.7 libemucore.so 0x81c1c0 (acceptance flag set outright)"
- name: ps2-0230a-20080220.rom1
path: bios/ps2-0230a-20080220.rom1
required: false
max_size: 4194304
description: "DVD player ROM"
note: >-
Tried as {bios}.rom1 then {biosbase}.rom1. Read at 0x2404000 of the EE
memory block and truncated to 4 MB. Logged and skipped when absent.
source_ref: "aethersx2/pcsx2/ps2/BiosTools.cpp:193-218, nethersx2-turnip-classic v0.7 libemucore.so 0x81b688-0x81b810"
- name: ps2-0230a-20080220.rom2
aliases:
- "SCPH-90006_BIOS_VX_HK _230.ROM2"
path: bios/ps2-0230a-20080220.rom2
required: false
max_size: 524288
description: "Chinese ROM extension"
note: >-
Same two-step naming as rom1. Read at 0x2804000 of the EE memory block and
truncated to 512 KB. Only present on Chinese region consoles.
source_ref: "aethersx2/pcsx2/ps2/BiosTools.cpp:193-218, nethersx2-turnip-classic v0.7 libemucore.so 0x81b820-0x81b994"
- name: ps2-0230a-20080220.nvm
path: bios/ps2-0230a-20080220.nvm
required: false
hle_fallback: true
min_size: 1024
validation: [size]
description: "Console NVRAM"
note: >-
Read at the BIOS path with the extension replaced by nvm, opened r+b.
Carries the console id, the iLink id, the language and the OSD
configuration. A 1024 byte image is written when the file is missing or
shorter, zeroed except for a fixed iLink id and the language defaults of
the BIOS region.
source_ref: "aethersx2/pcsx2/CDVD/CDVD.cpp:158-226, nethersx2-turnip-classic v0.7 libemucore.so 0x790470-0x7906c8, nethersx2-turnip-classic v0.7 libemucore.so 0x790820-0x790944"
- name: ps2-0230a-20080220.mec
path: bios/ps2-0230a-20080220.mec
required: false
hle_fallback: true
min_size: 4
validation: [size]
description: "Mechacon version"
note: >-
Read at the BIOS path with the extension replaced by mec. Written as
03 06 02 00 when the file is missing or shorter than 4 bytes.
source_ref: "aethersx2/pcsx2/CDVD/CDVD.cpp:120-144, nethersx2-turnip-classic v0.7 libemucore.so 0x791700-0x7918f4"
- name: eeprom.dat
required: false
hle_fallback: true
size: 64
description: "DEV9 EEPROM"
note: >-
Opened O_RDWR by bare name when the network adapter starts and mapped over
64 bytes. A compiled-in image stands in when the file is missing or cannot
be mapped.
source_ref: "aethersx2/pcsx2/DEV9/DEV9.cpp:73, aethersx2/pcsx2/DEV9/DEV9.cpp:145-160, nethersx2-turnip-classic v0.7 libemucore.so 0x7bb620-0x7bb680"
- name: flash.dat
required: false
hle_fallback: true
max_size: 8650752
description: "DEV9 SmartMedia flash image"
note: >-
Opened rb by bare name at network adapter init and read as 1024 blocks of
16 pages of 512 bytes plus 16 ECC bytes. The card is filled with 0xFF when
the file is absent.
source_ref: "aethersx2/pcsx2/DEV9/flash.cpp:76-103, nethersx2-turnip-classic v0.7 libemucore.so 0x7bb5cc-0x7bb61c"
- name: "<module>.irx"
required: false
unsourceable: "any IOP module the user points at, under no name the code expects"
description: "IOP module injected at boot"
note: >-
Opened at the path the configuration holds once it is four characters or
longer, and read into the ROM region at 0x3C0000, capped at 0x40000 bytes.
The field is empty by default and names no file of its own.
source_ref: "aethersx2/pcsx2/ps2/BiosTools.cpp:220-233, aethersx2/pcsx2/ps2/BiosTools.cpp:327-328, nethersx2-turnip-classic v0.7 libemucore.so 0x81b9a4-0x81bac4"
- name: libvulkad.so
path: lib/arm64-v8a/libvulkad.so
required: false
bundled: true
size: 484560
md5: 1a68e1ac1eec29005c19df924146cf19
sha1: 2655469eca935d89a6d8fe0c3998fe3ec0dd2d65
description: "Vulkan loader shim"
note: >-
Opened as libvulkad.so.1 then libvulkad.so where the stock library names
libvulkan.so, and vkCreateInstance is resolved from it. Without it the
Vulkan backend does not open and the message names the shim. This package
carries the build committed for v0.6, one revision behind the emulator
library beside it.
source_ref: "VulkanShim2/vulkan_shim.cpp:969-1272 (the constructor that runs on load), nethersx2-turnip-classic v0.7 libemucore.so 0x8a45ec-0x8a4624"
- name: libhook_impl.so
path: lib/arm64-v8a/libhook_impl.so
required: false
bundled: true
size: 461856
md5: c2a10d75f7a186f78debc79dd2204841
sha1: 5a86d24c83f4a0867a3526638182c8dc67e0033b
description: "Driver load hook"
note: >-
Opened into the adrenotools-libvulkan namespace and asked for
init_hook_param, which receives the driver directory and driver name. Its
hook_android_dlopen_ext is what replaces the vendor driver with the Turnip
one, and it reopens itself in each driver namespace it creates.
source_ref: "VulkanShim2/vulkan_shim.cpp:1138-1156, VulkanShim2/hook_impl.cpp:38-140"
- name: libmain_hook.so
path: lib/arm64-v8a/libmain_hook.so
required: false
bundled: true
size: 5648
md5: 3ded83b3f45773199b82bf81c86f8c89
sha1: e2ee6c00247fc05b88afe43237fa4bfa90212c54
description: "Namespace interposer"
note: >-
Loaded RTLD_GLOBAL into the same namespace before the system Vulkan
library, so its android_dlopen_ext and android_load_sphal_library are the
ones that library binds to.
source_ref: "VulkanShim2/vulkan_shim.cpp:1159-1160, VulkanShim2/main_hook.c:3-9"
- name: libvulkan_freedreno_T28.so
path: lib/arm64-v8a/libvulkan_freedreno_T28.so
required: false
bundled: true
size: 18606849
md5: 315f4b037b77dea81ea099e13e94fa11
sha1: 83406408d328d8529ffa2faf7ab878664a5c7a79
description: "Turnip driver, default branch"
note: >-
Chosen when no other branch matches. Loaded by name from the library
directory through the hook; a load failure falls back to the vendor
driver.
source_ref: "VulkanShim2/vulkan_shim.cpp:1011, VulkanShim2/vulkan_shim.cpp:1079-1080, VulkanShim2/hook_impl.cpp:127-135"
- name: libvulkan_freedreno_a8xx-turnip-gen8-V31.so
path: lib/arm64-v8a/libvulkan_freedreno_a8xx-turnip-gen8-V31.so
required: false
bundled: true
size: 14509832
md5: 7f6dbc9ec12cb53b1802c418cf532f9b
sha1: 2dc32726b7a68ced6a40ea2c6cc60848716907ab
description: "Turnip driver, Adreno 8xx branch"
note: >-
Chosen whenever the Adreno model reads non-zero, model 810 and 825
included. Model 825 also turns off framebuffer fetch.
source_ref: "VulkanShim2/vulkan_shim.cpp:1010, VulkanShim2/vulkan_shim.cpp:1037-1052, nethersx2-turnip-classic v0.7 libvulkad.so 0x22770-0x23108"
- name: libvulkan_freedreno_T24.so
path: lib/arm64-v8a/libvulkan_freedreno_T24.so
required: false
bundled: true
size: 18003849
md5: e90d691859e0ff8f0221f3fb497cca5d
sha1: d28f7c64a8296a6d1886b348946d01433c10b493
description: "Turnip driver, Adreno 810 branch"
note: >-
The Adreno 810 branch writes this path and the block it falls into
overwrites it with the 8xx driver before anything reads it, so this
revision never opens the file. The branch gained its own exit after the
revision this package was built from.
source_ref: "VulkanShim2/vulkan_shim.cpp:1039-1043, nethersx2-turnip-classic v0.7 libvulkad.so 0x22784-0x230d4"
- name: libvulkan_freedreno_25.3.0_R6_Gmem.so
path: lib/arm64-v8a/libvulkan_freedreno_25.3.0_R6_Gmem.so
required: false
bundled: true
size: 12048553
md5: 3f1b01295ab08d070bede8122ebd0aea
sha1: 2159a5172176f9ee0076370314d2d100de2fe1b1
description: "Turnip driver, Adreno 710 and 720 branch"
note: >-
Chosen when the model is unreadable and the GPU name holds 710 or 720.
source_ref: "VulkanShim2/vulkan_shim.cpp:1056-1059"
- name: libvulkan_freedreno_v24.1.0_R18.a6xx-Patched.so
path: lib/arm64-v8a/libvulkan_freedreno_v24.1.0_R18.a6xx-Patched.so
required: false
bundled: true
size: 9407968
md5: 7af55500464d372a609084fb4698e16d
sha1: 1abf76c578cb1330e354d5588634b87cef4bc057
description: "Turnip driver, SD845 to SD888 branch"
note: >-
Chosen when the platform reads SM8250, kona, SM8350, lahaina, sdm845 or
napali.
source_ref: "VulkanShim2/vulkan_shim.cpp:1027-1033"
- name: libvulkan_freedreno_T19.so
path: lib/arm64-v8a/libvulkan_freedreno_T19.so
required: false
bundled: true
size: 11581209
md5: 5f953080ba9ac858a99f3742c8302055
sha1: 4dc276dfd5842302c978ce9b2996f961dc6452f1
description: "Turnip driver, SM6125 branch"
note: "Chosen when the platform reads SM6125 or trinket."
source_ref: "VulkanShim2/vulkan_shim.cpp:1020-1023"
- name: libvulkan_freedreno.so
path: data/local/tmp/libvulkan_freedreno.so
required: false
unsourceable: "any Turnip build the user places at that path"
description: "Turnip driver override"
note: >-
Tested with access before any detection runs. When it exists it becomes
the driver and the driver directory becomes /data/local/tmp/, so none of
the six packed drivers is consulted.
source_ref: "VulkanShim2/vulkan_shim.cpp:1009, VulkanShim2/vulkan_shim.cpp:1012-1017"
- name: libbase.so
path: lib/arm64-v8a/libbase.so
required: false
bundled: true
size: 255352
md5: eae5ccb3f801b3333ec0e65592ce8a87
sha1: fecf95a804a7cb57e210f55d5482a56826c8684c
description: "Platform support library for the fallback path"
note: >-
Opened RTLD_GLOBAL from the library directory only when the namespace
approach failed and the shim falls back to patching the global offset
table.
source_ref: "VulkanShim2/vulkan_shim.cpp:1179-1194"
- name: libcutils.so
path: lib/arm64-v8a/libcutils.so
required: false
bundled: true
size: 91200
md5: 185cd93c21cce12ab4c3bc2430934684
sha1: 63e55bcae5ee690cf6bc7db69a5077c5502e4334
description: "Platform support library for the fallback path"
note: "Same fallback list as libbase.so, and a dependency of every packed driver."
source_ref: "VulkanShim2/vulkan_shim.cpp:1179-1194, VulkanShim2/vulkan_shim.cpp:1248-1255"
- name: libvndksupport.so
path: lib/arm64-v8a/libvndksupport.so
required: false
bundled: true
size: 66881
md5: aa5065cca6695aa4b8cfdd3c164f3d28
sha1: a6f2d8498a2f0a00776dd69c58f012cdbb75a308
description: "Platform support library for the fallback path"
note: >-
Same fallback list as libbase.so. Its android_load_sphal_library is the
call the shim stubs so a vendor load can be redirected.
source_ref: "VulkanShim2/vulkan_shim.cpp:1179-1194, VulkanShim2/vulkan_shim.cpp:1257-1269"
- name: libhardware.so
path: lib/arm64-v8a/libhardware.so
required: false
bundled: true
size: 66961
md5: 71e06a0726aa60b010e066d37021d36a
sha1: 555a6203cd7c23c2b49916d70615e5df7973aa87
description: "Platform support library for the fallback path"
note: "Same fallback list as libbase.so, and a dependency of every packed driver."
source_ref: "VulkanShim2/vulkan_shim.cpp:1179-1194, VulkanShim2/vulkan_shim.cpp:1235-1246"
- name: GameIndex.yaml
path: assets/GameIndex.yaml
required: false
bundled: true
size: 1758721
md5: 3f33de7bf8e40e00a05cf27c18a6be0c
sha1: 58fb1f8ea6cf2d526904349640453e682fe388a1
description: "Game database"
note: >-
Read from the package by name, keyed by serial, and carrying the per-game
fixes, patches and settings overrides. Parsed into gamedb.cache in the
cache folder.
source_ref: "aethersx2/pcsx2/GameDatabase.cpp:35, nethersx2-turnip-classic v0.7 libemucore.so 0x2e45fc"
- name: cheats_ws.zip
path: assets/cheats_ws.zip
required: false
bundled: true
size: 1694454
md5: cc19970629feb0a25b9b95263194f08f
sha1: 1caae7ddf0cbba5f1f6d7404b2309300d913778c
description: "Widescreen patch archive"
note: >-
Per-game pnach entries matched on the disc CRC, read from the package when
widescreen patches are enabled. The cheats_ws folder under the data
directory takes precedence and the archive is skipped when it holds a
match.
source_ref: "nethersx2-turnip-classic v0.7 libemucore.so 0x804464"
- name: cheats_ni.zip
path: assets/cheats_ni.zip
required: false
bundled: true
size: 223122
md5: fb2a43dcea094a19db4f4bcdc4ad32eb
sha1: 31cbff66380f255d359ff9ee09b6edc06102579a
description: "No-interlacing patch archive"
note: >-
Same form as cheats_ws.zip, read when no-interlacing patches are enabled,
with the cheats_ni folder taking precedence.
source_ref: "nethersx2-turnip-classic v0.7 libemucore.so 0x80460c"
- name: Roboto-Regular.ttf
path: assets/fonts/Roboto-Regular.ttf
required: true
bundled: true
size: 305608
md5: 86da78cb59576328483a11c6ef74bc2b
sha1: 00d62fbdc8d5dec4c659005e116d0ba2ee63b547
description: "Interface font"
note: "Read as the standard font when the interface comes up. An empty read aborts the process."
source_ref: "nethersx2-turnip-classic v0.7 libemucore.so 0x7d1e78-0x7d1e8c, nethersx2-turnip-classic v0.7 libemucore.so 0x7d2270"
- name: RobotoMono-Medium.ttf
path: assets/fonts/RobotoMono-Medium.ttf
required: true
bundled: true
size: 86820
md5: 8ad82b1dc550319993a7d6c932b2656d
sha1: 9056e59b69c6f1160fdfb92a0773f17f6307f3ad
description: "Fixed-width interface font"
note: "Read for the fixed-width font. An empty read aborts the process."
source_ref: "nethersx2-turnip-classic v0.7 libemucore.so 0x7d1ecc-0x7d1ee0, nethersx2-turnip-classic v0.7 libemucore.so 0x7d2270"
- name: fa-solid-900.ttf
path: assets/fonts/fa-solid-900.ttf
required: true
bundled: true
size: 204528
md5: dffd9504fcb1894620fa41c700172994
sha1: 694b8a2445ff39de415bf4791845442a7b1b81e5
description: "Font Awesome icon font"
note: "Read for the interface icon glyphs. An empty read aborts the process."
source_ref: "nethersx2-turnip-classic v0.7 libemucore.so 0x7d1f20-0x7d1f34, nethersx2-turnip-classic v0.7 libemucore.so 0x7d2270"
- name: ffx_a.h
path: assets/shaders/common/ffx_a.h
required: false
bundled: true
size: 161481
md5: 2c539b603dcb15dcdcfdc420eda56ced
sha1: 726370c10154ad092c15c251b98c79185e980c7c
description: "FidelityFX common header"
note: "Prepended to the sharpening shader of both backends."
source_ref: "nethersx2-turnip-classic v0.7 libemucore.so 0x627178"
- name: ffx_cas.h
path: assets/shaders/common/ffx_cas.h
required: false
bundled: true
size: 63512
md5: f8a3d7f48ae19fc372cd0d5d375d5a8d
sha1: a1d1a687577f7a607fda35bc88950f57c2129ca5
description: "FidelityFX CAS header"
note: "Prepended to the sharpening shader of both backends."
source_ref: "nethersx2-turnip-classic v0.7 libemucore.so 0x627188"
- name: fxaa.fx
path: assets/shaders/common/fxaa.fx
required: false
bundled: true
size: 19420
md5: 5cdeb2963c1b68c3ffb04a789cc66d6e
sha1: 3ac5f68049ed00d8ff3d2811bd09ef0c036efd0a
description: "FXAA shader source"
note: "Read by both backends when FXAA is enabled."
source_ref: "nethersx2-turnip-classic v0.7 libemucore.so 0x67c710, nethersx2-turnip-classic v0.7 libemucore.so 0x685fd0"
- name: common_header.glsl
path: assets/shaders/opengl/common_header.glsl
required: false
bundled: true
size: 1938
md5: 86a37e282f029d20f395cfd05263fddd
sha1: 9c391aae0daddf0c2ba3f0d5265aee9b491286e4
description: "OpenGL shader preamble"
note: "Prepended to every OpenGL program the renderer builds."
source_ref: "nethersx2-turnip-classic v0.7 libemucore.so 0x674618"
- name: convert.glsl
path: assets/shaders/opengl/convert.glsl
required: false
bundled: true
size: 10361
md5: 0dba3321d9f902439a50b79680b220c7
sha1: 26a17de3b4abc30e5c19987efad4ceac22e9a369
description: "OpenGL format conversion shader"
source_ref: "nethersx2-turnip-classic v0.7 libemucore.so 0x674f78"
- name: present.glsl
path: assets/shaders/opengl/present.glsl
required: false
bundled: true
size: 9458
md5: afbb9a89f17ead2d8ce7252c1b44186f
sha1: bf2688971a8ef2f2c262c3c2ec579d3dd39793e6
description: "OpenGL presentation shader"
source_ref: "nethersx2-turnip-classic v0.7 libemucore.so 0x675480"
- name: merge.glsl
path: assets/shaders/opengl/merge.glsl
required: false
bundled: true
size: 455
md5: 2c4d70f62928eac933eec932d7bfa0b3
sha1: d1a3c11a1273e1d6c740e4eacc3159842f206683
description: "OpenGL frame merge shader"
source_ref: "nethersx2-turnip-classic v0.7 libemucore.so 0x675780"
- name: interlace.glsl
path: assets/shaders/opengl/interlace.glsl
required: false
bundled: true
size: 6246
md5: 0e537dd838a7ecd3b687f3f7cc60a7be
sha1: e74e58f530abb4af02c0875c2f04d507e854869e
description: "OpenGL deinterlacing shader"
source_ref: "nethersx2-turnip-classic v0.7 libemucore.so 0x675aac"
- name: shadeboost.glsl
path: assets/shaders/opengl/shadeboost.glsl
required: false
bundled: true
size: 1457
md5: 3d1e2be521a66cbfc2c5ff32057e7bf4
sha1: 8d8b8966afd2ad840151f7fcb494739041708c89
description: "OpenGL brightness and contrast shader"
source_ref: "nethersx2-turnip-classic v0.7 libemucore.so 0x675cb8"
- name: cas.glsl
path: assets/shaders/opengl/cas.glsl
required: false
bundled: true
size: 2448
md5: f8a684763e24557c97e3f5d05935bb3b
sha1: 1a69a0fc522caff98fc3829ebf3f12a6a006a058
description: "OpenGL sharpening shader"
source_ref: "nethersx2-turnip-classic v0.7 libemucore.so 0x676fa0"
- name: tfx_vgs.glsl
path: assets/shaders/opengl/tfx_vgs.glsl
required: false
bundled: true
size: 5756
md5: a97e9616f298bb9041bf9e45ee2ec597
sha1: 0e9e98f766c9250b465af776d0077f49f797fed2
description: "OpenGL texture function vertex and geometry shader"
source_ref: "nethersx2-turnip-classic v0.7 libemucore.so 0x677318"
- name: tfx_fs.glsl
path: assets/shaders/opengl/tfx_fs.glsl
required: false
bundled: true
size: 25906
md5: 9d80855607a6da1014f083340741b845
sha1: 919c3308c8850852d529d0127ce94e873375bfd2
description: "OpenGL texture function fragment shader"
source_ref: "nethersx2-turnip-classic v0.7 libemucore.so 0x677328"
- name: tfx.glsl
path: assets/shaders/vulkan/tfx.glsl
required: false
bundled: true
size: 28290
md5: ebc0ffa3de6fd0a7a4dea17f8b74d806
sha1: b4ebf3f7f20fc88f91cda033552a7489a9ff179c
description: "Vulkan texture function shader"
source_ref: "nethersx2-turnip-classic v0.7 libemucore.so 0x682098"
- name: convert.glsl
path: assets/shaders/vulkan/convert.glsl
required: false
bundled: true
size: 8025
md5: 553d33859963a1abe5508e8e45f1cb1e
sha1: 7a133d4cf115dc49cd1921bd7049ea64ad58acce
description: "Vulkan format conversion shader"
source_ref: "nethersx2-turnip-classic v0.7 libemucore.so 0x68394c, nethersx2-turnip-classic v0.7 libemucore.so 0x685fb8"
- name: present.glsl
path: assets/shaders/vulkan/present.glsl
required: false
bundled: true
size: 8177
md5: 72626d625bb963c6cd7074d4dfd0adda
sha1: 4871ee00b249b41d16232769e2f661bedd1c83db
description: "Vulkan presentation shader"
source_ref: "nethersx2-turnip-classic v0.7 libemucore.so 0x684728"
- name: interlace.glsl
path: assets/shaders/vulkan/interlace.glsl
required: false
bundled: true
size: 6707
md5: bf3caa2532873593218bc4a09e924d4e
sha1: f8d14d80036f11707c7e94db2a77531d582019dd
description: "Vulkan deinterlacing shader"
source_ref: "nethersx2-turnip-classic v0.7 libemucore.so 0x684f74"
- name: merge.glsl
path: assets/shaders/vulkan/merge.glsl
required: false
bundled: true
size: 669
md5: b776383d21609db24d5348c381c2c286
sha1: b09de39d6459c70ffab28dcb3e3ef879b1648674
description: "Vulkan frame merge shader"
source_ref: "nethersx2-turnip-classic v0.7 libemucore.so 0x6857c4"
- name: shadeboost.glsl
path: assets/shaders/vulkan/shadeboost.glsl
required: false
bundled: true
size: 1741
md5: 366b45b6c4e9ed8e6b7454eebcb5d010
sha1: 26b29f57685d8108cf519c4f1d340d43aacbff6e
description: "Vulkan brightness and contrast shader"
source_ref: "nethersx2-turnip-classic v0.7 libemucore.so 0x686284"
- name: cas.glsl
path: assets/shaders/vulkan/cas.glsl
required: false
bundled: true
size: 2624
md5: 56f3cf4de895dd4d32d6c79d564d0c5b
sha1: 709fd5393188f7cff0fe4230d0e3e8b69a82f5b9
description: "Vulkan sharpening shader"
source_ref: "nethersx2-turnip-classic v0.7 libemucore.so 0x6869c4"
- name: unlock.wav
path: assets/sounds/achievements/unlock.wav
required: false
bundled: true
size: 87714
md5: 4d035ee86f836bfed422a975cf65c9cc
sha1: eb488a76217629f620e40287567d7e2b30337680
description: "Achievement unlock sound"
note: >-
Joined to the file:///android_asset base and handed to playSoundAsync,
which opens it from the package and plays it through MediaPlayer.
source_ref: "nethersx2-turnip-classic v0.7 libemucore.so 0x811190"
- name: lbsubmit.wav
path: assets/sounds/achievements/lbsubmit.wav
required: false
bundled: true
size: 82096
md5: fa6a7030a9f259ee7300dd0bd49f24f3
sha1: 5ad1e110dcf0ffd26405981398892a82e4f3bad1
description: "Leaderboard submission sound"
source_ref: "nethersx2-turnip-classic v0.7 libemucore.so 0x811814"
- name: message.wav
path: assets/sounds/achievements/message.wav
required: false
bundled: true
size: 15696
md5: d66b0bccd743bd11eaca55bcaec925da
sha1: c54f04b63ac6f04e0a0944ef260b5497e4494dbd
description: "Achievement notification sound"
source_ref: "nethersx2-turnip-classic v0.7 libemucore.so 0x810254"
- name: placeholder.png
path: assets/placeholder.png
required: false
bundled: true
size: 2762
md5: 8f846541ccbf088ee7f8c49c8dcb3a6a
sha1: c36292ab7e16bf5a6cbc4063f638e24872349c45
description: "Fallback interface texture"
note: >-
Requested from the texture cache when a notification or a loading screen
has no image of its own. A miss logs that it cannot continue and the
caller tears the interface down instead of bringing it up.
source_ref: "nethersx2-turnip-classic v0.7 libemucore.so 0x7d21fc, nethersx2-turnip-classic v0.7 libemucore.so 0x817be0, nethersx2-turnip-classic v0.7 libemucore.so 0x7ec54c"
- name: "<region>.png"
path: assets/icons/flags/NTSC-U.png
required: false
bundled: true
description: "Game list region flag"
note: >-
Loaded as icons/flags/<region>.png with the region string of the entry.
Thirty are carried, seven NTSC and twenty-two PAL plus Other.
source_ref: "nethersx2-turnip-classic v0.7 classes.dex icons/flags/%s.png"
- name: "star-<rating>.png"
path: assets/icons/star-0.png
required: false
bundled: true
description: "Game list compatibility rating icon"
note: "Loaded as icons/star-<rating>.png for ratings 0 to 5."
source_ref: "nethersx2-turnip-classic v0.7 classes.dex icons/star-%d.png"
- name: faq.html
path: assets/faq.html
required: false
bundled: true
size: 14048
md5: c2a64e0bcc401da9b0a3c7adf3cff410
sha1: 9163d4a3d19b87483f843e4bf3afe236a50a72d2
description: "Help page"
note: "Opened under the android_asset scheme by the setup wizard's browser view."
source_ref: "nethersx2-turnip-classic v0.7 classes.dex android_asset faq.html"
- name: 3rdparty.html
path: assets/3rdparty.html
required: false
bundled: true
size: 90296
md5: fb4ff036f3e4769aa6daefdc4c5dba57
sha1: 7743bf1d7e6e09a02f1b2972aa63bd8a9f26050d
description: "Third party notices page"
note: "Opened under the android_asset scheme in the built-in browser view."
source_ref: "nethersx2-turnip-classic v0.7 classes.dex android_asset 3rdparty.html"
exclusion_note: >
Left out are the libraries the package carries for the dynamic linker rather
than for its own code. libc.so, libm.so, libdl.so, ld-android.so, liblog.so
and libc++_shared.so sit beside the drivers so the namespace built over that
directory can satisfy their DT_NEEDED, and no code path names any of them;
android_linker_ns.o is a relocatable object nothing can open. libc++.so and
libsync.so are named in the fallback and promote arrays but the package
carries neither, and the promote call passes RTLD_NOLOAD, which never reads
from disk. libfile_redirect_hook.so and libgsl_alloc_hook.so are reachable
only under feature flags the shim never sets, the only flag passed being the
custom driver one. The system Vulkan loader and libandroid.so come from the
platform. Also left out are the assets no code path on this platform opens:
game_controller_db.txt, whose name appears in neither the library nor the dex,
pad input arriving through handleControllerButtonEvent and
handleControllerAxisEvent; the seven Direct3D shader sources under
shaders/dx11; icons/AppIconLarge.png and cover-placeholder.png;
fonts/Roboto-Regular-copyright and sounds/achievements/README.txt, which are
licence and credit texts; and dexopt/baseline.prof and baseline.profm, which
the Android runtime consumes. Everything the emulator produces for itself
under the data directory is out as well: memory cards as Mcd<nnn>.ps2 and
Mcd-Multitap<n>-Slot<nn>.ps2, DEV9hdd.raw for the internal disk, save states,
screenshots, covers, texture dumps, playtime.dat, emulog.txt, imgui.ini,
per-game settings, input profiles, the gamedb and gl_programs caches, and
vulkan_shim.log.
ref: VulkanShim2/vulkan_shim.cpp:1099-1105, VulkanShim2/vulkan_shim.cpp:1150,
VulkanShim2/vulkan_shim.cpp:1179-1194,
nethersx2-turnip-classic v0.7 libemucore.so 0x4a8c7c
+801
View File
@@ -0,0 +1,801 @@
emulator: NetherSX2-Turnip
type: standalone
core_classification: community_fork
bios_mode: agnostic
source: "https://github.com/nckstwrt/NetherSX2-Turnip"
upstream: "https://github.com/Trixarian/AetherSX2"
author: "nckstwrt"
profiled_date: "2026-08-12"
source_commit: "3b7cf800ccac4ab5af768aee24b04363bedeb711"
upstream_commit: "1d1f795dfc70e38da67724c7298779260f513889"
core_version: "2.2n-4248-Turnip-v0.7"
display_name: "Sony - PlayStation 2 (NetherSX2-Turnip)"
mode: standalone
cores:
- "nethersx2-turnip"
- "NetherSX2-Turnip"
- "NETHERSX2-TURNIP"
systems:
- sony-playstation-2
bios_directory: "bios/"
notes: |
PlayStation 2 emulator for Android, package xyz.aethersx2.tturnip, activity
xyz.aethersx2.android.EmulationActivity. The application id is the only part
of the package name that changes, which is what lets it sit beside the build
it derives from. That build is NetherSX2 v2.2n-4248, itself a patch of the
AetherSX2 v1.5-4248 package, and the library still reports itself as
NetherSX2 v2.2n-4248 (Patched). The project publishes its shim sources and
the libraries it packs; lib/libvulkad.so, lib/libhook_impl.so and
lib/libmain_hook.so at the pinned revision are byte for byte the ones in the
v0.7 package, so the sources describe the shipped binaries. Everything below
was read from that package: lib/arm64-v8a/libemucore.so, libvulkad.so, the
dex and the assets.
ref: VulkanShim2/compile2.bat:21-64,
nethersx2-turnip v0.7 AndroidManifest.xml,
nethersx2-turnip v0.7 libemucore.so 0xe180c
The patch rewrites twenty places in the 4248 library. Three are the strings
libvulkan.so, libvulkan.so.1 and the message naming them, each turned into
libvulkad.so, so the Vulkan loader opens the shim instead of the system
driver. Twelve turn comparisons into unconditional paths, among them the
memchr scan for the twenty-two byte pattern that precedes the certificate
test and two byte-wise string comparisons whose result is forced to equal,
which is what lets the package be resigned under a new application id. One
skips the notification built from the android_warning key. The last four move
settings defaults: the renderer enum from 12 to 14, the upscale multiplier
fallback from 1.0 to 2.0 with the configuration read short-circuited, the
hardware download mode default, and the warning text that went with it. None
of them is in a file loading path, so the file set below is that of the
package it patches, read from this library rather than carried over.
ref: nethersx2-turnip v0.7 libemucore.so 0x10728e,
nethersx2-turnip v0.7 libemucore.so 0x83cebc-0x83cee4,
nethersx2-turnip v0.7 libemucore.so 0x83b728,
nethersx2-turnip v0.7 libemucore.so 0x83bb3c,
nethersx2-turnip v0.7 libemucore.so 0x83cfbc,
nethersx2-turnip v0.7 libemucore.so 0x80e910,
nethersx2-turnip v0.7 libemucore.so 0x840ff4,
nethersx2-turnip v0.7 libemucore.so 0x84130c,
nethersx2-turnip v0.7 libemucore.so 0x8421a0
A BIOS image is required and boot stops without one, the application saying
it needs a PS2 BIOS in the bios folder of the data directory. The data
directory is getExternalFilesDir(null) with getDataDir() behind it, so it
follows the application id, and the folder names under it come from the
Folders section, Bios defaulting to bios.
ref: nethersx2-turnip v0.7 libemucore.so 0xf70a9,
nethersx2-turnip v0.7 libemucore.so 0x7ea908-0x7ea930,
xyz/aethersx2/android/NativeLibrary getExternalFilesDir
Detection is by content. The scan lists the BIOS folder with a * mask, keeps
files between 4194304 and 8388608 bytes, and accepts an image whose romdir
carries a RESET entry followed by a readable ROMVER; the fifth ROMVER
character gives the zone, A for USA, C for China, E for Europe, H for Asia,
J for Japan, P for Free, T for T10K and X for Test, any other character
standing for itself. The sixth character is compared against D and the result
discarded, the acceptance flag being set outright, so development images pass.
An image named in the configuration is combined with the BIOS folder and
opened at that path when it exists, without the size filter and without the
romdir test. No name and no hash is matched anywhere. The image is read into
the 4 MB ROM region and truncated to it.
ref: aethersx2/pcsx2/ps2/BiosTools.cpp:27-28,
aethersx2/pcsx2/ps2/BiosTools.cpp:62-145,
aethersx2/pcsx2/ps2/BiosTools.cpp:235-260,
aethersx2/pcsx2/ps2/BiosTools.cpp:272-322,
nethersx2-turnip v0.7 libemucore.so 0x828d80-0x828f14,
nethersx2-turnip v0.7 libemucore.so 0x829140-0x8292f4
Companions derive from the selected image. rom1 and rom2 are appended to the
full name first, then substituted for the existing extension, so an image at
ps2-0230a-20080220.bin is followed by ps2-0230a-20080220.bin.rom1 then
ps2-0230a-20080220.rom1. The nvm and the mec are read at the substituted
extension only, and both are written with defaults when they are absent or
too short. No erom is loaded on this code line.
ref: aethersx2/pcsx2/ps2/BiosTools.cpp:193-216,
aethersx2/pcsx2/CDVD/CDVD.cpp:120-144,
aethersx2/pcsx2/CDVD/CDVD.cpp:158-214,
nethersx2-turnip v0.7 libemucore.so 0x8288b0-0x828bb8
The network adapter opens eeprom.dat and flash.dat by bare name, so they
resolve against the process working directory, which the application never
sets. A compiled-in image stands in for the first and a card filled with 0xFF
for the second. DEV9hdd.raw is the default name of the empty disk image its
settings page writes. An IRX named in the configuration is read into the ROM
region at 0x3C0000 at boot; the field is empty by default and names no file
of its own.
ref: aethersx2/pcsx2/DEV9/DEV9.cpp:146-161,
aethersx2/pcsx2/DEV9/flash.cpp:76-103,
aethersx2/pcsx2/ps2/BiosTools.cpp:220-233,
nethersx2-turnip v0.7 libemucore.so 0x7c5bec-0x7c5ca0,
nethersx2-turnip v0.7 libemucore.so 0x828bb8-0x828ca8
The Vulkan path is the reason this build exists. libemucore.so opens
libvulkad.so where the stock library opens libvulkan.so, and that shim reads
the Adreno model from the kgsl sysfs nodes, picks one of six Turnip drivers
packed beside it, creates a linker namespace over its own library directory
and loads libhook_impl.so and libmain_hook.so into it. The system
/system/lib64/libvulkan.so is then opened inside that namespace with its
soname patched, so its own driver load lands in the hook, which opens the
chosen Turnip driver instead of the vendor ICD. A driver present at
/data/local/tmp/libvulkan_freedreno.so is tested first and wins over all six.
When the namespace cannot be built the shim falls back to patching the
system library's global offset table, and that path alone loads libbase.so,
libcutils.so, libvndksupport.so and libhardware.so from the library
directory. The shim appends to vulkan_shim.log under the files folder of the
data directory.
ref: VulkanShim2/vulkan_shim.cpp:43-73,
VulkanShim2/vulkan_shim.cpp:1010-1092,
VulkanShim2/vulkan_shim.cpp:1099-1171,
VulkanShim2/vulkan_shim.cpp:1186-1204,
VulkanShim2/hook_impl.cpp:38-139,
nethersx2-turnip v0.7 libemucore.so 0x8b473c-0x8b4768
Resources are read out of the package itself. The library has no asset
manager of its own and calls back into readPackageFile, readPackageFileToString
and playSoundAsync, each taking an asset-relative name, so the game database,
the patch archives, the interface fonts, the shader sources every backend
compiles at startup and the achievement sounds are versioned with the build
and never looked for on disk. The game list draws its region flags and rating
stars from the same assets. Four of the Vulkan shader sources differ from the
ones the package it patches carries.
ref: nethersx2-turnip v0.7 libemucore.so 0x8348d0,
xyz/aethersx2/android/NativeLibrary readPackageFile,
xyz/aethersx2/android/NativeLibrary playSoundAsync
files:
- name: ps2-0230a-20080220.bin
path: bios/ps2-0230a-20080220.bin
required: true
min_size: 4194304
max_size: 8388608
validation: [size]
description: "PS2 BIOS image"
note: >-
Any image whose romdir holds RESET and a readable ROMVER is accepted,
whatever its name. The 4 to 8 MB range gates the folder scan; an image
named in the configuration skips both that range and the romdir test.
source_ref: "aethersx2/pcsx2/ps2/BiosTools.cpp:27-28, aethersx2/pcsx2/ps2/BiosTools.cpp:235-260, nethersx2-turnip v0.7 libemucore.so 0x828e20-0x828e44 (size window), nethersx2-turnip v0.7 libemucore.so 0x829244-0x829248 (device type result discarded)"
- name: ps2-0230a-20080220.rom1
path: bios/ps2-0230a-20080220.rom1
required: false
max_size: 4194304
description: "DVD player ROM"
note: >-
Tried as {bios}.rom1 then {biosbase}.rom1. Read at 0x2404000 of the EE
memory block and truncated to 4 MB. Logged and skipped when absent.
source_ref: "aethersx2/pcsx2/ps2/BiosTools.cpp:193-216, nethersx2-turnip v0.7 libemucore.so 0x8288b0-0x828a24"
- name: ps2-0230a-20080220.rom2
aliases:
- "SCPH-90006_BIOS_VX_HK _230.ROM2"
path: bios/ps2-0230a-20080220.rom2
required: false
max_size: 524288
description: "Chinese ROM extension"
note: >-
Same two-step naming as rom1. Read at 0x2804000 of the EE memory block and
truncated to 512 KB. Only present on Chinese region consoles.
source_ref: "aethersx2/pcsx2/ps2/BiosTools.cpp:193-216, nethersx2-turnip v0.7 libemucore.so 0x828a34-0x828ba8"
- name: ps2-0230a-20080220.nvm
path: bios/ps2-0230a-20080220.nvm
required: false
hle_fallback: true
min_size: 1024
validation: [size]
description: "Console NVRAM"
note: >-
Read at the BIOS path with the extension replaced by nvm, opened r+b.
Carries the console id, the iLink id, the language and the OSD
configuration. A 1024 byte image is written when the file is missing or
shorter, zeroed except for a fixed iLink id and the language defaults of
the BIOS region.
source_ref: "aethersx2/pcsx2/CDVD/CDVD.cpp:158-214, nethersx2-turnip v0.7 libemucore.so 0x79b930-0x79ba68"
- name: ps2-0230a-20080220.mec
path: bios/ps2-0230a-20080220.mec
required: false
hle_fallback: true
min_size: 4
validation: [size]
description: "Mechacon version"
note: >-
Read at the BIOS path with the extension replaced by mec. Written as
03 06 02 00 when the file is missing or shorter than 4 bytes.
source_ref: "aethersx2/pcsx2/CDVD/CDVD.cpp:120-144, nethersx2-turnip v0.7 libemucore.so 0x79cbd0-0x79cc20"
- name: eeprom.dat
required: false
hle_fallback: true
size: 64
description: "DEV9 EEPROM"
note: >-
Opened O_RDWR by bare name when the network adapter starts and mapped over
64 bytes. A compiled-in image stands in when the file is missing or cannot
be mapped.
source_ref: "aethersx2/pcsx2/DEV9/DEV9.cpp:146-161, nethersx2-turnip v0.7 libemucore.so 0x7c5c44"
- name: flash.dat
required: false
hle_fallback: true
max_size: 8650752
description: "DEV9 SmartMedia flash image"
note: >-
Opened rb by bare name at network adapter init and read as 1024 blocks of
16 pages of 512 bytes plus 16 ECC bytes. The card is filled with 0xFF when
the file is absent.
source_ref: "aethersx2/pcsx2/DEV9/flash.cpp:76-103, nethersx2-turnip v0.7 libemucore.so 0x7c5bf0"
- name: "<module>.irx"
required: false
unsourceable: "any IOP module the user points at, under no name the code expects"
description: "IOP module injected at boot"
note: >-
Opened at the path the configuration holds once it is longer than three
characters, and read into the ROM region at 0x3C0000, capped at 0x40000
bytes. The field is empty by default and names no file of its own.
source_ref: "aethersx2/pcsx2/ps2/BiosTools.cpp:220-233, aethersx2/pcsx2/ps2/BiosTools.cpp:327-328, nethersx2-turnip v0.7 libemucore.so 0x828bb8-0x828ca8"
- name: libvulkad.so
path: lib/arm64-v8a/libvulkad.so
required: false
bundled: true
size: 484528
md5: 07a891beadc7c3baf4b98b7358cc6e2c
sha1: 55f845c4ea0262cfdc4882a3caccc6848c4f0a6b
description: "Vulkan loader shim"
note: >-
Opened as libvulkad.so.1 then libvulkad.so where the stock library names
libvulkan.so, and vkCreateInstance is resolved from it. Without it the
Vulkan backend does not open and the message names the shim.
source_ref: "VulkanShim2/vulkan_shim.cpp:971-1279 (the constructor that runs on load), nethersx2-turnip v0.7 libemucore.so 0x8b473c-0x8b4768"
- name: libhook_impl.so
path: lib/arm64-v8a/libhook_impl.so
required: false
bundled: true
size: 461856
md5: c2a10d75f7a186f78debc79dd2204841
sha1: 5a86d24c83f4a0867a3526638182c8dc67e0033b
description: "Driver load hook"
note: >-
Opened into the adrenotools-libvulkan namespace and asked for
init_hook_param, which receives the driver directory and driver name. Its
hook_android_dlopen_ext is what replaces the vendor driver with the Turnip
one, and it reopens itself in each driver namespace it creates.
source_ref: "VulkanShim2/vulkan_shim.cpp:1145-1163, VulkanShim2/hook_impl.cpp:38-139"
- name: libmain_hook.so
path: lib/arm64-v8a/libmain_hook.so
required: false
bundled: true
size: 5648
md5: 3ded83b3f45773199b82bf81c86f8c89
sha1: e2ee6c00247fc05b88afe43237fa4bfa90212c54
description: "Namespace interposer"
note: >-
Loaded RTLD_GLOBAL into the same namespace before the system Vulkan
library, so its android_dlopen_ext and android_load_sphal_library are the
ones that library binds to.
source_ref: "VulkanShim2/vulkan_shim.cpp:1166-1167, VulkanShim2/main_hook.c:3-8"
- name: libvulkan_freedreno_T28.so
path: lib/arm64-v8a/libvulkan_freedreno_T28.so
required: false
bundled: true
size: 18606849
md5: 315f4b037b77dea81ea099e13e94fa11
sha1: 83406408d328d8529ffa2faf7ab878664a5c7a79
description: "Turnip driver, default branch"
note: >-
Chosen when no other branch matches. Loaded by name from the library
directory through the hook; a load failure falls back to the vendor
driver.
source_ref: "VulkanShim2/vulkan_shim.cpp:1014, VulkanShim2/vulkan_shim.cpp:1086-1087, VulkanShim2/hook_impl.cpp:127-135"
- name: libvulkan_freedreno_a8xx-turnip-gen8-V31.so
path: lib/arm64-v8a/libvulkan_freedreno_a8xx-turnip-gen8-V31.so
required: false
bundled: true
size: 14509832
md5: 7f6dbc9ec12cb53b1802c418cf532f9b
sha1: 2dc32726b7a68ced6a40ea2c6cc60848716907ab
description: "Turnip driver, Adreno 8xx branch"
note: >-
Chosen when the Adreno model reads non-zero and is not 810. Model 825 also
turns off framebuffer fetch.
source_ref: "VulkanShim2/vulkan_shim.cpp:1013, VulkanShim2/vulkan_shim.cpp:1041-1058"
- name: libvulkan_freedreno_T24.so
path: lib/arm64-v8a/libvulkan_freedreno_T24.so
required: false
bundled: true
size: 18003849
md5: e90d691859e0ff8f0221f3fb497cca5d
sha1: d28f7c64a8296a6d1886b348946d01433c10b493
description: "Turnip driver, Adreno 810 branch"
note: "Chosen when the Adreno model reads 810."
source_ref: "VulkanShim2/vulkan_shim.cpp:1043-1046"
- name: libvulkan_freedreno_25.3.0_R6_Gmem.so
path: lib/arm64-v8a/libvulkan_freedreno_25.3.0_R6_Gmem.so
required: false
bundled: true
size: 12048553
md5: 3f1b01295ab08d070bede8122ebd0aea
sha1: 2159a5172176f9ee0076370314d2d100de2fe1b1
description: "Turnip driver, Adreno 710 and 720 branch"
note: >-
Chosen when the model is unreadable and the GPU name holds 710 or 720, or
the platform reads SM6475.
source_ref: "VulkanShim2/vulkan_shim.cpp:1062-1065"
- name: libvulkan_freedreno_v24.1.0_R18.a6xx-Patched.so
path: lib/arm64-v8a/libvulkan_freedreno_v24.1.0_R18.a6xx-Patched.so
required: false
bundled: true
size: 9407968
md5: 7af55500464d372a609084fb4698e16d
sha1: 1abf76c578cb1330e354d5588634b87cef4bc057
description: "Turnip driver, SM8250 and SM7325 branch"
note: "Chosen when the platform reads SM8250, kona or SM7325."
source_ref: "VulkanShim2/vulkan_shim.cpp:1030-1037"
- name: libvulkan_freedreno_T19.so
path: lib/arm64-v8a/libvulkan_freedreno_T19.so
required: false
bundled: true
size: 11581209
md5: 5f953080ba9ac858a99f3742c8302055
sha1: 4dc276dfd5842302c978ce9b2996f961dc6452f1
description: "Turnip driver, SM6125 branch"
note: "Chosen when the platform reads SM6125 or trinket."
source_ref: "VulkanShim2/vulkan_shim.cpp:1023-1026"
- name: libvulkan_freedreno.so
path: data/local/tmp/libvulkan_freedreno.so
required: false
unsourceable: "any Turnip build the user places at that path"
description: "Turnip driver override"
note: >-
Tested with access before any detection runs. When it exists it becomes
the driver and the driver directory becomes /data/local/tmp/, so none of
the six packed drivers is consulted.
source_ref: "VulkanShim2/vulkan_shim.cpp:1012, VulkanShim2/vulkan_shim.cpp:1015-1020"
- name: libbase.so
path: lib/arm64-v8a/libbase.so
required: false
bundled: true
size: 255352
md5: eae5ccb3f801b3333ec0e65592ce8a87
sha1: fecf95a804a7cb57e210f55d5482a56826c8684c
description: "Platform support library for the fallback path"
note: >-
Opened RTLD_GLOBAL from the library directory only when the namespace
approach failed and the shim falls back to patching the global offset
table.
source_ref: "VulkanShim2/vulkan_shim.cpp:1186-1201"
- name: libcutils.so
path: lib/arm64-v8a/libcutils.so
required: false
bundled: true
size: 91200
md5: 185cd93c21cce12ab4c3bc2430934684
sha1: 63e55bcae5ee690cf6bc7db69a5077c5502e4334
description: "Platform support library for the fallback path"
note: "Same fallback list as libbase.so, and a dependency of every packed driver."
source_ref: "VulkanShim2/vulkan_shim.cpp:1186-1201"
- name: libvndksupport.so
path: lib/arm64-v8a/libvndksupport.so
required: false
bundled: true
size: 66881
md5: aa5065cca6695aa4b8cfdd3c164f3d28
sha1: a6f2d8498a2f0a00776dd69c58f012cdbb75a308
description: "Platform support library for the fallback path"
note: >-
Same fallback list as libbase.so. Its android_load_sphal_library is the
call the shim stubs so a vendor load can be redirected.
source_ref: "VulkanShim2/vulkan_shim.cpp:1186-1201, VulkanShim2/vulkan_shim.cpp:742-750"
- name: libhardware.so
path: lib/arm64-v8a/libhardware.so
required: false
bundled: true
size: 66961
md5: 71e06a0726aa60b010e066d37021d36a
sha1: 555a6203cd7c23c2b49916d70615e5df7973aa87
description: "Platform support library for the fallback path"
note: "Same fallback list as libbase.so, and a dependency of every packed driver."
source_ref: "VulkanShim2/vulkan_shim.cpp:1186-1201"
- name: GameIndex.yaml
path: assets/GameIndex.yaml
required: false
bundled: true
size: 1850565
md5: 26ab10d8de93c9b9806fa7602faa2b62
sha1: fca26d4f7c1fe0abf6534b470da2ee5ad461eba5
description: "Game database"
note: >-
Read from the package by name, keyed by serial, and carrying the per-game
fixes, patches and settings overrides. Parsed into gamedb.cache in the
cache folder.
source_ref: "aethersx2/pcsx2/GameDatabase.cpp:35, nethersx2-turnip v0.7 libemucore.so 0x2e35e4"
- name: cheats_ws.zip
path: assets/cheats_ws.zip
required: false
bundled: true
size: 1694454
md5: cc19970629feb0a25b9b95263194f08f
sha1: 1caae7ddf0cbba5f1f6d7404b2309300d913778c
description: "Widescreen patch archive"
note: >-
Per-game pnach entries matched on the disc CRC, read from the package when
widescreen patches are enabled. The cheats_ws folder under the data
directory takes precedence and the archive is skipped when it holds a
match.
source_ref: "nethersx2-turnip v0.7 libemucore.so 0x80f8e4"
- name: cheats_ni.zip
path: assets/cheats_ni.zip
required: false
bundled: true
size: 223122
md5: fb2a43dcea094a19db4f4bcdc4ad32eb
sha1: 31cbff66380f255d359ff9ee09b6edc06102579a
description: "No-interlacing patch archive"
note: >-
Same form as cheats_ws.zip, read when no-interlacing patches are enabled,
with the cheats_ni folder taking precedence.
source_ref: "nethersx2-turnip v0.7 libemucore.so 0x80fa8c"
- name: Roboto-Regular.ttf
path: assets/fonts/Roboto-Regular.ttf
required: true
bundled: true
size: 305608
md5: 86da78cb59576328483a11c6ef74bc2b
sha1: 00d62fbdc8d5dec4c659005e116d0ba2ee63b547
description: "Interface font"
note: "Read as the standard font when the interface comes up. The load fails without it."
source_ref: "nethersx2-turnip v0.7 libemucore.so 0xf6f27"
- name: RobotoMono-Medium.ttf
path: assets/fonts/RobotoMono-Medium.ttf
required: true
bundled: true
size: 86820
md5: 8ad82b1dc550319993a7d6c932b2656d
sha1: 9056e59b69c6f1160fdfb92a0773f17f6307f3ad
description: "Fixed-width interface font"
note: "Read for the fixed-width font. The load fails without it."
source_ref: "nethersx2-turnip v0.7 libemucore.so 0xdb98d"
- name: fa-solid-900.ttf
path: assets/fonts/fa-solid-900.ttf
required: true
bundled: true
size: 204528
md5: dffd9504fcb1894620fa41c700172994
sha1: 694b8a2445ff39de415bf4791845442a7b1b81e5
description: "Font Awesome icon font"
note: "Read for the interface icon glyphs. The load fails without it."
source_ref: "nethersx2-turnip v0.7 libemucore.so 0x11a567"
- name: ffx_a.h
path: assets/shaders/common/ffx_a.h
required: false
bundled: true
size: 161481
md5: 2c539b603dcb15dcdcfdc420eda56ced
sha1: 726370c10154ad092c15c251b98c79185e980c7c
description: "FidelityFX common header"
note: "Prepended to the sharpening shader of both backends."
source_ref: "nethersx2-turnip v0.7 libemucore.so 0x10cfb5"
- name: ffx_cas.h
path: assets/shaders/common/ffx_cas.h
required: false
bundled: true
size: 63512
md5: f8a3d7f48ae19fc372cd0d5d375d5a8d
sha1: a1d1a687577f7a607fda35bc88950f57c2129ca5
description: "FidelityFX CAS header"
note: "Prepended to the sharpening shader of both backends."
source_ref: "nethersx2-turnip v0.7 libemucore.so 0xce5f7"
- name: fxaa.fx
path: assets/shaders/common/fxaa.fx
required: false
bundled: true
size: 19420
md5: 5cdeb2963c1b68c3ffb04a789cc66d6e
sha1: 3ac5f68049ed00d8ff3d2811bd09ef0c036efd0a
description: "FXAA shader source"
note: "Read by both backends when FXAA is enabled."
source_ref: "nethersx2-turnip v0.7 libemucore.so 0xe4f55"
- name: common_header.glsl
path: assets/shaders/opengl/common_header.glsl
required: false
bundled: true
size: 1863
md5: 1dcf4ca0cc95f2f8e11b66c2ffeeaffe
sha1: 3f47597187030144498af7a92531e8f205561211
description: "OpenGL shader preamble"
note: "Prepended to every OpenGL program the renderer builds."
source_ref: "nethersx2-turnip v0.7 libemucore.so 0x10cfcc"
- name: convert.glsl
path: assets/shaders/opengl/convert.glsl
required: false
bundled: true
size: 11276
md5: c3db4fcdd142912c0d9a07f3fb40bbbc
sha1: b2a059787ee297654b27f633e37382e239693a36
description: "OpenGL format conversion shader"
source_ref: "nethersx2-turnip v0.7 libemucore.so 0xb5bd7"
- name: present.glsl
path: assets/shaders/opengl/present.glsl
required: false
bundled: true
size: 9458
md5: afbb9a89f17ead2d8ce7252c1b44186f
sha1: bf2688971a8ef2f2c262c3c2ec579d3dd39793e6
description: "OpenGL presentation shader"
source_ref: "nethersx2-turnip v0.7 libemucore.so 0x11a06b"
- name: merge.glsl
path: assets/shaders/opengl/merge.glsl
required: false
bundled: true
size: 455
md5: 2c4d70f62928eac933eec932d7bfa0b3
sha1: d1a3c11a1273e1d6c740e4eacc3159842f206683
description: "OpenGL frame merge shader"
source_ref: "nethersx2-turnip v0.7 libemucore.so 0x117b1c"
- name: interlace.glsl
path: assets/shaders/opengl/interlace.glsl
required: false
bundled: true
size: 6246
md5: 0e537dd838a7ecd3b687f3f7cc60a7be
sha1: e74e58f530abb4af02c0875c2f04d507e854869e
description: "OpenGL deinterlacing shader"
source_ref: "nethersx2-turnip v0.7 libemucore.so 0x103b11"
- name: shadeboost.glsl
path: assets/shaders/opengl/shadeboost.glsl
required: false
bundled: true
size: 1457
md5: 3d1e2be521a66cbfc2c5ff32057e7bf4
sha1: 8d8b8966afd2ad840151f7fcb494739041708c89
description: "OpenGL brightness and contrast shader"
source_ref: "nethersx2-turnip v0.7 libemucore.so 0x1007b6"
- name: cas.glsl
path: assets/shaders/opengl/cas.glsl
required: false
bundled: true
size: 2448
md5: f8a684763e24557c97e3f5d05935bb3b
sha1: 1a69a0fc522caff98fc3829ebf3f12a6a006a058
description: "OpenGL sharpening shader"
source_ref: "nethersx2-turnip v0.7 libemucore.so 0x10967c"
- name: tfx_vgs.glsl
path: assets/shaders/opengl/tfx_vgs.glsl
required: false
bundled: true
size: 5756
md5: a97e9616f298bb9041bf9e45ee2ec597
sha1: 0e9e98f766c9250b465af776d0077f49f797fed2
description: "OpenGL texture function vertex and geometry shader"
source_ref: "nethersx2-turnip v0.7 libemucore.so 0xd49ab"
- name: tfx_fs.glsl
path: assets/shaders/opengl/tfx_fs.glsl
required: false
bundled: true
size: 26680
md5: 24e39ca8f97a1ee4cbd1e9bf8b8da2fd
sha1: 00eb0418e7a25c89aaf7c526922fe45d83243ec5
description: "OpenGL texture function fragment shader"
source_ref: "nethersx2-turnip v0.7 libemucore.so 0x117b36"
- name: tfx.glsl
path: assets/shaders/vulkan/tfx.glsl
required: false
bundled: true
size: 29670
md5: df60c4e6c5690dd2d3a0cc740800b284
sha1: 1c3a966a42cefcb9c26ce2fa77e4cd90f2d50329
description: "Vulkan texture function shader"
note: "This project's own bytes, neither the New nor the Old copy it also carries."
source_ref: "nethersx2-turnip v0.7 libemucore.so 0xe14fc"
- name: convert.glsl
path: assets/shaders/vulkan/convert.glsl
required: false
bundled: true
size: 9379
md5: f3aaf5697b069d1eb9be66fc1c932786
sha1: aedc25c370bf3fe28923dc8359111a098293a503
description: "Vulkan format conversion shader"
note: "This project's own bytes, neither the New nor the Old copy it also carries."
source_ref: "nethersx2-turnip v0.7 libemucore.so 0xc3d36"
- name: interlace.glsl
path: assets/shaders/vulkan/interlace.glsl
required: false
bundled: true
size: 7745
md5: 08bc6e44a6d86ccad4b0673b445bd9d8
sha1: 5a433c891e071c3885af7a5f7e47fed7e5ec30cf
description: "Vulkan deinterlacing shader"
note: "This project's own bytes, neither the New nor the Old copy it also carries."
source_ref: "nethersx2-turnip v0.7 libemucore.so 0xb86eb"
- name: cas.glsl
path: assets/shaders/vulkan/cas.glsl
required: false
bundled: true
size: 2637
md5: deb7394a31184990c78c9753a293ff60
sha1: 005cecf1a5e20b05407d55d0aad22cf81ad66c31
description: "Vulkan sharpening shader"
note: "The New copy the project also carries, byte for byte."
source_ref: "nethersx2-turnip v0.7 libemucore.so 0xd4a2c"
- name: present.glsl
path: assets/shaders/vulkan/present.glsl
required: false
bundled: true
size: 8177
md5: 72626d625bb963c6cd7074d4dfd0adda
sha1: 4871ee00b249b41d16232769e2f661bedd1c83db
description: "Vulkan presentation shader"
source_ref: "nethersx2-turnip v0.7 libemucore.so 0xd777a"
- name: merge.glsl
path: assets/shaders/vulkan/merge.glsl
required: false
bundled: true
size: 669
md5: b776383d21609db24d5348c381c2c286
sha1: b09de39d6459c70ffab28dcb3e3ef879b1648674
description: "Vulkan frame merge shader"
source_ref: "nethersx2-turnip v0.7 libemucore.so 0xe8c36"
- name: shadeboost.glsl
path: assets/shaders/vulkan/shadeboost.glsl
required: false
bundled: true
size: 1741
md5: 366b45b6c4e9ed8e6b7454eebcb5d010
sha1: 26b29f57685d8108cf519c4f1d340d43aacbff6e
description: "Vulkan brightness and contrast shader"
source_ref: "nethersx2-turnip v0.7 libemucore.so 0xde3c2"
- name: unlock.wav
path: assets/sounds/achievements/unlock.wav
required: false
bundled: true
size: 87714
md5: 4d035ee86f836bfed422a975cf65c9cc
sha1: eb488a76217629f620e40287567d7e2b30337680
description: "Achievement unlock sound"
note: "Handed to playSoundAsync, which opens it from the package and plays it through MediaPlayer."
source_ref: "nethersx2-turnip v0.7 libemucore.so 0xceb85"
- name: lbsubmit.wav
path: assets/sounds/achievements/lbsubmit.wav
required: false
bundled: true
size: 82096
md5: fa6a7030a9f259ee7300dd0bd49f24f3
sha1: 5ad1e110dcf0ffd26405981398892a82e4f3bad1
description: "Leaderboard submission sound"
source_ref: "nethersx2-turnip v0.7 libemucore.so 0xe1a29"
- name: message.wav
path: assets/sounds/achievements/message.wav
required: false
bundled: true
size: 15696
md5: d66b0bccd743bd11eaca55bcaec925da
sha1: c54f04b63ac6f04e0a0944ef260b5497e4494dbd
description: "Achievement notification sound"
source_ref: "nethersx2-turnip v0.7 libemucore.so 0xfd47d"
- name: placeholder.png
path: assets/placeholder.png
required: false
bundled: true
size: 2762
md5: 8f846541ccbf088ee7f8c49c8dcb3a6a
sha1: c36292ab7e16bf5a6cbc4063f638e24872349c45
description: "Fallback interface texture"
note: >-
Requested from the texture cache when a notification or a loading screen
has no image of its own.
source_ref: "nethersx2-turnip v0.7 libemucore.so 0x7dcbf4, nethersx2-turnip v0.7 libemucore.so 0x8238e0"
- name: "<region>.png"
path: assets/icons/flags/NTSC-U.png
required: false
bundled: true
description: "Game list region flag"
note: >-
Loaded as icons/flags/<region>.png with the region string of the entry.
Thirty are carried, seven NTSC and twenty-two PAL plus Other.
source_ref: "nethersx2-turnip v0.7 classes.dex icons/flags/%s.png"
- name: "star-<rating>.png"
path: assets/icons/star-0.png
required: false
bundled: true
description: "Game list compatibility rating icon"
note: "Loaded as icons/star-<rating>.png for ratings 0 to 5."
source_ref: "nethersx2-turnip v0.7 classes.dex icons/star-%d.png"
- name: faq.html
path: assets/faq.html
required: false
bundled: true
size: 14048
md5: c2a64e0bcc401da9b0a3c7adf3cff410
sha1: 9163d4a3d19b87483f843e4bf3afe236a50a72d2
description: "Help page"
note: "Opened under the android_asset scheme in the built-in browser view."
source_ref: "nethersx2-turnip v0.7 classes.dex android_asset faq.html"
- name: 3rdparty.html
path: assets/3rdparty.html
required: false
bundled: true
size: 90296
md5: fb4ff036f3e4769aa6daefdc4c5dba57
sha1: 7743bf1d7e6e09a02f1b2972aa63bd8a9f26050d
description: "Third party notices page"
note: "Opened under the android_asset scheme in the built-in browser view."
source_ref: "nethersx2-turnip v0.7 classes.dex android_asset 3rdparty.html"
exclusion_note: >
Left out are the libraries the package carries for the dynamic linker rather
than for its own code. libc.so, libm.so, libdl.so, ld-android.so and
libc++_shared.so sit beside the drivers so the namespace built over that
directory can satisfy their DT_NEEDED, and no code path names any of them;
android_linker_ns.o is a relocatable object nothing can open. libc++.so and
libsync.so are named in the fallback and promote arrays but the package
carries neither, and the promote call passes RTLD_NOLOAD, which never reads
from disk. libnativewindow.so, libsync.so and libz.so, which every driver
needs, come from the system through the link to the default namespace. The
deps cache the shim would fill under cache/vulkan_deps is unreachable: the
functions that build it have no call site and the compiler dropped their
strings. Also left out are the assets no code path on this platform opens:
shaders/vulkan/New and shaders/vulkan/Old, reference copies for which no path
string exists in the library; game_controller_db.txt, whose name appears in
neither the library nor the dex, pad input arriving through
handleControllerButtonEvent and handleControllerAxisEvent; the seven Direct3D
shader sources under shaders/dx11; icons/AppIconLarge.png and
cover-placeholder.png; fonts/Roboto-Regular-copyright and
sounds/achievements/README.txt, which are licence and credit texts; and
dexopt/baseline.prof and baseline.profm, which the Android runtime consumes.
Everything the emulator produces for itself under the data directory is out
as well: memory cards as Mcd<nnn>.ps2, DEV9hdd.raw for the internal disk,
save states, screenshots, covers, texture dumps, per-game settings, input
profiles, the gamedb and pipeline caches, and vulkan_shim.log.
ref: VulkanShim2/vulkan_shim.cpp:599-729, VulkanShim2/vulkan_shim.cpp:1107-1112,
VulkanShim2/vulkan_shim.cpp:1186-1201,
nethersx2-turnip v0.7 libvulkad.so
-2
View File
@@ -15,8 +15,6 @@ cores:
- "nethersx2"
- "NetherSX2"
- "NETHERSX2"
- "NETHERSX2-TURNIP"
- "NETHERSX2-TURNIP-CLASSIC"
systems:
- sony-playstation-2
+76
View File
@@ -0,0 +1,76 @@
emulator: "NGP.emu"
type: standalone
core_classification: community_fork
source: "https://github.com/Rakashazi/emu-ex-plus-alpha"
upstream: "https://mednafen.github.io/"
profiled_date: "2026-08-12"
source_commit: "1c12fac5ce49badaadff2e2f210dcc30b89f4943"
core_version: "1.5.85"
display_name: "SNK - Neo Geo Pocket / Color (NGP.emu)"
mode: standalone
cores:
- "ngp-emu"
- "NGP.emu"
- "NGP-EMU"
systems:
- snk-ngp
- snk-ngpc
notes: |
Member of the EX Emulator series by Robert Broglia, which targets Android and
Linux (README.md:1,3-4,12-13) and keeps iOS and Pandora build shortcuts in the
tree (NGP.emu/ios.mk, NGP.emu/pandora.mk). Published as com.explusalpha.NgpEmu
(NGP.emu/metadata/conf.mk:2,4,6,7) and reached by ES-DE through its NGP-EMU
find rule, which only the Android rule set carries. Mednafen's Neo Geo Pocket
module, itself descended from NeoPop, is vendored under NGP.emu/src/ngp
(NGP.emu/metadata/conf.mk:8, NGP.emu/src/main/AppMeta.cc:27) on the 1.32 line
(EmuFramework/include/shared/mednafen/mednafen-config.h:167) and driven by the
app's own video, audio, input and save layers. Three files differ from the
Mednafen 1.32.1 release, all of it frontend plumbing: the pixel format and
sound rate hooks, the input latch and the flash file I/O move to the app
(NGP.emu/src/main/Main.cc:84,102,118-131, NGP.emu/src/main/system.ccm:87,93).
The TLCS-900h disassembler is left out of the build
(NGP.emu/src/CMakeLists.txt:6-32). Content is read from .ngp, .ngc, .npc and
.ngpc files (NGP.emu/metadata/conf.mk:5, NGP.emu/src/main/AppMeta.cc:31-34,
NGP.emu/src/ngp/neopop.cpp:336-337); an archive is opened by the framework,
which keeps the first entry passing that same filter
(EmuFramework/src/EmuSystem.cc:392-412).
The content image is the only one the app loads. It is read into a 4 MiB
buffer, hashed for the save file names and handed to the module, which refuses
an image over 8 MiB (NGP.emu/src/main/Main.cc:80-85,
EmuFramework/src/shared/mednafen-emuex/MDFNUtils.hh:133-146,
NGP.emu/src/ngp/neopop.cpp:183-193). The BIOS is built in memory rather than
read: bios_install fills a 64 KiB array with the 27 system call vectors, writes
opcode 0x1F at each target, copies an 0x800 byte system font held in the binary
to 0x8DCF and closes the image with a RETI and an infinite loop
(NGP.emu/src/ngp/bios.cpp:29,50-180,182-239, NGP.emu/src/ngp/neopop.cpp:211).
That opcode is bound to the HLE handler in the interpreter decode table, and
the handler answers only from the 0xFF0000 region
(NGP.emu/src/ngp/TLCS-900h/TLCS900h_interpret.cpp:921-926,
NGP.emu/src/ngp/biosHLE.cpp:43-47). The same array is what the memory map
returns for the BIOS region and where the font routine reads its glyphs
(NGP.emu/src/ngp/mem.cpp:121, NGP.emu/src/ngp/biosHLE.cpp:221). The NGP
Language menu item feeds the ngp.language setting, written to RAM at boot
rather than selecting a file (NGP.emu/src/main/EmuMenuViews.cc:31-40,
NGP.emu/src/main/options.cc:82-83, NGP.emu/src/ngp/mem.cpp:620,
NGP.emu/src/ngp/neopop.cpp:286-299).
No firmware path exists by construction: the app answers Mednafen's file name
request for save states, saves and save backups only, and any other kind ends
in unreachable() (NGP.emu/src/main/options.cc:96-106). Cheat loading and IPS
patching are compiled in from the shared Mednafen sources and called from
nowhere (EmuFramework/src/shared/mednafen/mempatcher.cpp:251-254,
EmuFramework/src/shared/mednafen/file.cpp:38-53). Per content the app writes
and reads back a .ngf image holding the cartridge flash, plus save states and
NgpEmu.config (NGP.emu/src/main/Main.cc:53-73,118-131,
NGP.emu/src/main/system.ccm:76, NGP.emu/src/main/AppMeta.cc:28). ui.png,
gpOverlay.png and the shader sources are drawn from the application bundle
(EmuFramework/include/emuframework/AssetManager.hh:61-66,
EmuFramework/src/AssetManager.cc:58-65,
EmuFramework/src/VideoImageEffect.cc:163-173). The app declares no bundled
content, the framework definition defaulting to an empty span
(EmuFramework/src/AppMeta.cc:40,
EmuFramework/include/emuframework/AppMeta.hh:66-68).
files: []
+78
View File
@@ -0,0 +1,78 @@
emulator: openbor
type: standalone
core_classification: game_engine
source: "https://github.com/DCurrent/openbor"
upstream: "https://github.com/DCurrent/openbor"
profiled_date: "2026-08-12"
source_commit: "0ece95d1c113c1ce86f2da826b3c25b521ee116d"
core_version: "4.0 Build 7949"
display_name: "OpenBOR Game Engine"
cores:
- openbor
- openbor4432
- openbor6330
- openbor6412
- openbor6510
- openbor7142
- openbor7530
systems:
- openbor
mode: standalone
notes: |
Sprite based side scrolling engine continuing Senile Team's Beats of Rage,
built for beat em up and shooter style 2D games. A game is a module: a .pak
archive carrying its own data tree, and that archive is what the frontends
hand over as content. ES-DE runs the .pak on macOS, the game's own AppImage,
.exe or .lnk on Linux and Windows, and opens the engine UI on Android since
the package takes no file argument. Batocera runs OpenBOR<build> <rom> after
reading a four digit build tag out of the file name in openborGenerator.py,
which is why it packages several engine versions side by side. RetroDECK
launches the 4.0 Linux AppImage, RetroBat runs OpenBOR.exe from a per build
folder.
packfile holds "bor.pak" until argv[1] names a path that exists, and with no
such argument the built in menu lists Paks/ and the player picks one
(engine/sdl/sdlport.c:25,124-135, engine/sdl/menu.c:172-203,802).
packfile_supported accepts any name containing .pak and skips menu.pak
(engine/source/gamelib/packfile.c:1577-1584).
Everything read for a running game comes out of that module. buffer_pakfile
tries the real filesystem first through fopen, then the same path inside the
archive (engine/openbor.c:921-965,969-1018), so data/models.txt,
data/levels.txt, data/video.txt, data/menu.txt, the scene scripts and the
sprites and sounds under data/ resolve either from an unpacked data/ directory
beside the binary (engine/source/gamelib/packfile.c:781-810) or from the pak.
Four names take precedence over their in-pak copy when they exist on disk:
translation/translation.txt and translation/menu.txt over data/translation.txt
(engine/source/gamelib/translation.c:102-106, engine/openbor.c:5975,53240),
saves/lifebar.txt over data/lifebar.txt (engine/openbor.c:4965-4972), and on
Android Saves/<module>/touch.txt then Saves/touch.txt over data/touch.txt
(engine/android/app/jni/openbor/video.c:210-218). Each holds text or a control
layout written for one module. The engine/translation.txt copied into the
release folder by CMakeLists.txt:239 is a blank msgid template whose own first
line sends it to the module data folder, and the published Windows archive for
v7533 contains only OpenBOR.exe.
Startup reads nothing. Logo, menu and log viewer artwork are PNG byte arrays
compiled in from engine/resources (engine/sdl/menu.c:20-27), menu text draws
from the embedded hankaku face (engine/sdl/menu.c:16,228), the GLSL fragment
shaders are string literals (engine/sdl/opengl.c:45-116), and the Android
touch skin is a header (engine/android/app/jni/openbor/video.c:49). No gamepad
mapping file is read, nothing is dlopened at runtime, the Android package
ships an empty assets directory, and the SecurePAK paths compile out of every
build because no build file defines SPK_SUPPORTED
(engine/source/gamelib/packfile.c:36, engine/source/gamelib/packfile.h:9,135).
Files the engine writes rather than expects: Paks, Saves, Logs and ScreenShots
are created at startup when missing (engine/sdl/sdlport.c:30-33,119-122),
settings and progress land in Saves as <module>.cfg, .sav, .hi, .scr and .inp
alongside default.cfg (engine/source/utils.c:284-312,
engine/openbor.c:2675-3040), and the viewer reads back Logs/OpenBorLog.txt and
Logs/ScriptLog.txt (engine/source/utils.c:47-62, engine/sdl/menu.c:652-700).
paks/logoff.txt is a marker whose existence alone skips the startup logo, so
the player creates it empty (engine/sdl/menu.c:707-716). Module script can
open any path it names through openfilestream
(engine/openborscript.c:10505-10600).
files: []
+72
View File
@@ -0,0 +1,72 @@
emulator: pce-emu
type: standalone
core_classification: community_fork
source: "https://github.com/Rakashazi/emu-ex-plus-alpha"
upstream: "https://mednafen.github.io/"
profiled_date: "2026-08-12"
source_commit: "1c12fac5ce49badaadff2e2f210dcc30b89f4943"
core_version: "1.5.85"
display_name: "PCE.emu"
cores: ["pce-emu", "PCE.emu", "pceemu", "PCE-EMU", "com.PceEmu"]
systems: [nec-pc-engine, nec-pc-engine-cd, nec-supergrafx]
verification: existence
notes: >
Android and desktop application by Robert Broglia built on EmuFramework,
vendoring Mednafen's pce_fast and pce modules. Both are compiled and
selectable at runtime; pce_fast is what an unset core option resolves to
(system.ccm:125).
HuCard content (.pce, .sgx) loads with no external file. CD content
(.cue, .toc, .ccd, .chd) requires a System Card image: loadContent throws
"No System Card Set" when the path is unset or the file is gone
(Main.cc:88-91).
The System Card is a single path the user picks through a file browser
filtered to .pce and .sgx (EmuMenuViews.cc:176-191), stored as
CFGKEY_SYSCARD_PATH. No filename is fixed and no directory is scanned.
MDFN_GetSettingS returns an empty string for pce.cdbios, pce_fast.cdbios
and pce.gecdbios, and MDFN_MakeFName answers every MDFNMKF_FIRMWARE
request with that one path (options.cc:275-301), so the Games Express
branch reads whichever image the setting points at. Mednafen's settings
table still carries the syscard3.pce and gecard.pce defaults but
settings.cpp is not compiled, so they are never read.
A path with an archive extension is opened as an archive and the first
member ending in .pce, .bin or .bios is used (MDFNFILE.cc:41-76).
Neither module hashes the image. pce_fast skips a 512-byte copier header
then reads a fixed 262144 bytes (huc.cpp:299-302); pce reads
min(rounded length, length) and accepts any size (huc.cpp:225-316).
HuC_Load is always called with SYSCARD_3, or SYSCARD_ARCADE when Arcade
Card emulation is on (pce.cpp:653).
SuperGrafx is enabled by the .sgx extension, by a CRC match against the
built-in sgx_table (pce.cpp:345, 382-395), or by DetectSGXCD on disc.
HES playback is compiled out (pce.cpp:76) and cheats are disabled
(options.cc:245-246).
files:
- name: "syscard3.pce"
description: "Super CD-ROM2 System Card 3.0"
required: true
validation: [existence, size]
min_size: 262144
category: bios
source_ref: "src/main/Main.cc:80-91 (throws without it), src/main/options.cc:275-301 (path resolution), src/main/EmuMenuViews.cc:176-191 (selection), src/pce_fast/pce.cpp:477-483 + src/pce_fast/huc.cpp:284-304 (default module load), src/pce/pce.cpp:645-653 (accurate module load), src/pce_fast/pce.cpp:663 + src/pce/pce.cpp:1094 (name)"
note: >
min_size comes from the fixed 262144-byte read in pce_fast
(huc.cpp:302) with Stream::read throwing on a short file
(Stream.h:88); a 262656-byte dump passes through the copier-header
skip at huc.cpp:299. The pce module imposes no minimum.
- name: "gecard.pce"
description: "Games Express CD Card"
required: false
validation: [existence]
category: bios
source_ref: "src/pce/pce.cpp:512-551 (DetectGECD), src/pce/pce.cpp:644-646 (gecdbios branch), src/pce/huc.cpp:225-316 (size-agnostic read), src/pce/pce.cpp:1095 (name)"
note: >
Reached only when the accurate module runs and DetectGECD matches the
disc; pce_fast has no Games Express branch. Served through the same
System Card setting, so the user points it at this image to boot those
discs.
+85
View File
@@ -0,0 +1,85 @@
emulator: "Pizza Boy GBA"
type: standalone
core_classification: embedded_hle
source: "https://play.google.com/store/apps/details?id=it.dbtecno.pizzaboygbapro"
upstream: closed-source
author: "Pizza Emulators"
profiled_date: "2026-08-12"
core_version: "2.8.13"
display_name: "Nintendo - Game Boy Advance (Pizza Boy GBA)"
mode: standalone
cores:
- "pizza-boy-gba"
- "Pizza Boy GBA"
- "PIZZA-BOY-GBA"
systems:
- nintendo-gba
notes: |
Two Android packages, closed source, sold and given away on Google Play under the
Pizza Boy A name, reached by ES-DE through its PIZZA-BOY-GBA find rule and started
with the game passed as the rom_uri extra: it.dbtecno.pizzaboygbapro, the paid build
the rule names first, and it.dbtecno.pizzaboygba, the free one. Two Play distribution
builds are read here, both carrying the source stamp: Pro 2.8.13 (versionCode 343,
Play App Signing certificate sha256
6b5547246e41921f25eba8abb1bc018729c4f0b8db029debbd3380a2b1ec2fe1), which supplies the
Java and the resources, and Basic 2.3.3 (versionCode 236, developer certificate sha256
b3ee584096acf4667bb9346daa9cce19237ef7ce95c99e9260ac89be0f7d6130, CN=Davide Berra,
O=DBTecno), whose arm64-v8a libpizzaboy-jni.so ships DWARF and an unstripped symbol
table and supplies every native reference below as its own file and line. Java line
numbers are those of Pro 2.8.13. Two rebuilt copies of Pro 1.35.11 were rejected on
their certificate, one signed C=debugging with no source stamp and one signed
O=APKMODY. 69 of the 77 native methods the Pro declares are exported by the Basic
core, the three BIOS entry points among them: one core, compiled per package.
One system is emulated, Game Boy Advance: the core is built from a tree named
pizzaboyadvance whose compilation units carry gba.c and no Game Boy core, and the
three Game Boy Color and Super Game Boy methods the Pro still declares are among the
eight the library does not export.
The BIOS is the one file the user supplies, and it is read only while Load BIOS file
is on, off by default; the picker and the Run BIOS animation switch, on by default,
both depend on that box (res/xml/pref_general.xml). In the free package the same
three preferences are declared android:enabled="false".
A per rom Low precision BIOS set to On clears the stored path and makes the core keep
its own replacement, and one cartridge, checksum 0xc7d89508, forces the same at load
time. When a real image is installed the boot animation starts execution at 0 rather
than at the cartridge entry, and a multiplayer session exchanges the CRC32 of the file
so that both peers run the same one.
Everything else the app opens it makes itself: boxart.db and cheat.db are created by
their own CREATE TABLE, the default skins, the shaders and the cheat descriptors are
raw resources unpacked at first run, and <rom>.keys is an input recording. The
obfuscated assets are PairIP tamper protection.
files:
- name: gba_bios.bin
system: nintendo-gba
required: false
hle_fallback: true
has_builtin: true
agnostic: true
size: 16384
config_key: "bios_file"
description: "Game Boy Advance BIOS"
note: >-
Chosen from any location under any name through the document picker, or, when the
picked document is named .zip, taken from its first entry; the legacy browser
offers .gba, .bin and .zip and writes the entry it extracts to bios.bin under the
application directory. The absolute path is stored and handed to the library,
which copies it into a 256 byte buffer. At load time the 16 KB BIOS area is first
filled with a 744 byte replacement compiled into the library, then, if the path is
set, the file is opened and up to 16384 bytes are read over it and a flag records
that a real image is installed. Nothing about the file is examined: any read
returning at least one byte is accepted, and no size, name or hash test exists on
either side of the bridge. A read of zero bytes leaves the replacement in place
and logs "Cannot read BIOS file".
source_ref: "Pizza Boy GBA Pro 2.8.13 SettingsActivity.java:116-140 (import), :143-183
(preference and picker), FileDialog.java:57,72,77,846-857 (legacy browser, zip entry
to bios.bin), Common.java:85-105 (copy to temp), :160-190 (single entry unzip),
MainActivity.java:833,835,865 (bridge), :10936-10941 (gate and handoff),
res/xml/pref_general.xml (defaults); Pizza Boy A Basic 2.3.3 libpizzaboy-jni.so
pizza.c:932-938 (path buffer), :945-946 (boot flag), :632-642 (low precision BIOS),
global.c:93-95 (defaults), mmu.c:1522-1543 (replacement, gate, read, flag),
:2106-2110 (forced HLE), cpu.c:40 (boot vector)"
+130
View File
@@ -0,0 +1,130 @@
emulator: "Pizza Boy GBC"
type: standalone
core_classification: embedded_hle
source: "https://play.google.com/store/apps/details?id=it.dbtecno.pizzaboypro"
upstream: closed-source
author: "Pizza Emulators"
profiled_date: "2026-08-12"
core_version: "6.0.6"
display_name: "Nintendo - Game Boy / Color (Pizza Boy GBC)"
mode: standalone
cores:
- "pizza-boy-gbc"
- "Pizza Boy GBC"
- "PIZZA-BOY-GBC"
systems:
- nintendo-gb
- nintendo-gbc
- nintendo-sgb
notes: |
Two Android packages, closed source, sold and given away on Google Play under the
Pizza Boy C name, reached by ES-DE through its PIZZA-BOY-GBC find rule and started
with the game passed as the rom_uri extra: it.dbtecno.pizzaboypro, the paid build the
rule names first, and it.dbtecno.pizzaboy, the free one. Two Play distribution builds
are read here, both carrying the developer certificate sha256
b3ee584096acf4667bb9346daa9cce19237ef7ce95c99e9260ac89be0f7d6130 (CN=Davide Berra,
O=DBTecno) and a source stamp: Pro 6.0.6 (versionCode 231), which supplies the Java
and the resources, and Basic 4.1.6 (versionCode 202), whose arm64-v8a
libpizzaboy-jni.so ships DWARF and an unstripped symbol table and supplies every
native reference below as its own file and line. Java line numbers are those of Pro
6.0.6. The Pro on the store is 7.4.5 (versionCode 324) and no genuine copy of it is
reachable: apkcombo bounces the download page of a paid app back to the app page,
apkvision carries no copy, and archive.org holds 6.0.6 alone. The Pro ships its core
as a stripped armeabi-v7a build; it carries the same log strings and the same
constants as the Basic core, the 64 KB clear, the 8192 byte read cap, the 256 byte
header copy and the 256 and 2304 byte gate, and 65 of the 70 entry points it exports
are exported by the Basic core as well. The Pro also ships libpizza-jni.so, an
older core exporting the free package JNI names and carrying no BIOS entry point,
which no loadLibrary call reaches.
Three systems are emulated from one tree named pizzaboy, whose compilation units
carry gameboy.c, mmu.c, sgb.c and camera.c: Game Boy, Game Boy Color and Super Game
Boy. The SGB command set, borders and palettes are handled by sgb.c behind a Super
Game Boy switch that is on by default, with a preference that gives Game Boy Color
precedence over Super Game Boy on a cartridge that offers both. camera.c drives the
Game Boy Camera cartridge from the device camera, and the Game Boy Printer is served
over the link port.
The boot ROM is the one file the user supplies, in two slots, Gameboy Classic ROMs
BIOS and Gameboy Color ROMs BIOS, and it is read only while Load BIOS file is on,
off by default (res/xml/pref_general.xml:89-99). In the free package the same three
preferences are declared android:enabled="false" behind a paid badge. A ROM whose
name ends in .gb or .sgb takes the first slot, every other name takes the second.
The library never examines the name, the extension or the content: the byte count of
the read decides the machine. A file of 256 bytes runs the cartridge as a Game Boy,
one of 2304 bytes as a Game Boy Color, and any other length is refused with "Unknown
BIOS file", after which the run continues with the boot skipped. The image is read
into a second MMU whose 0x100 to 0x1FF window is overwritten with the cartridge
header from the active one, the program counter starts at 0 instead of at the
cartridge entry, and the animation runs until it reaches 0x100, at which point the
active MMU returns to the cartridge and the accumulator is restored. A multiplayer
session exchanges the CRC32 of the Game Boy slot so that both peers run the same
file.
Everything else the app opens it makes itself: the default skins and the cheat
descriptors are raw resources unpacked at first run, the box art, cheat, sticker,
layout and per-ROM databases are created by their own CREATE TABLE, and the save
states, the RTC files, the screenshots and the GIF captures are outputs. No boot ROM
is compiled into the library: neither Game Boy image nor the Nintendo logo appears
anywhere in the loaded sections, and the post-boot register state comes from the
reset path instead.
files:
- name: dmg_boot.bin
system: nintendo-gb
required: false
hle_fallback: true
agnostic: true
size: 256
validation: [size]
config_key: "bios_file"
description: "Game Boy (DMG) boot ROM"
note: >-
Chosen from any location under any name through the document picker and copied
into the application directory under the name the picker reports; the legacy
browser offers .gbc, .gb, .bin and .zip and writes the entry it extracts from a
zip to bios.bin. The absolute path is stored and handed to the library, which
copies it into a 256 byte buffer. It is used when the ROM name ends in .gb or
.sgb, and only on the first run of that ROM and with no multiplayer peer
connected. The file is read into a second MMU image, up to 8192 bytes, and a
count of exactly 256 starts the run as a Game Boy, keeping the default palette.
Nothing else is examined: no name, size range, header or hash test exists on
either side of the bridge, and a count that is neither 256 nor 2304 is refused.
A multiplayer session exchanges the CRC32 of this file so that both peers run
the same one.
source_ref: "Pizza Boy GBC Pro 6.0.6 MainActivity.java:702 (native method),
:8067-8081 (gate and slot selection), :1734-1757 (CRC32 of the file),
:1907, :2136 (multiplayer handshake), SettingsActivity.java:40-41 (request
codes), :96-113 (picker result and copy), :116-192 (both preferences),
Common.java:42 (copy to the application directory), FileDialog.java:949-975
(legacy browser, zip entry to bios.bin), res/xml/pref_general.xml:89-99
(defaults); Pizza Boy C Basic 4.1.6 libpizzaboy-jni.so pizza.c:1023-1024 (path
into global_bios_file), global.c:28 (char[256]), mmu.c:431-463 (open, 64 KB
clear, 8192 byte read, cartridge header copy, 256 and 2304 gate, refusal),
gameboy.c:1161-1168 (conditions and call), :1171, :1238 (failure),
:1179-1198 (model, MMU switch, program counter at 0, accumulator),
:1201-1235 (run to 0x100, return to the cartridge)"
- name: cgb_boot.bin
system: nintendo-gbc
required: false
hle_fallback: true
agnostic: true
size: 2304
validation: [size]
config_key: "bios_file_cgb"
description: "Game Boy Color (CGB) boot ROM"
note: >-
Same picker, same copy and same handoff as the Game Boy slot, used for every ROM
whose name does not end in .gb or .sgb. A count of exactly 2304 starts the run as
a Game Boy Color, which sets the accumulator to 0x11 and keeps the hardware
palettes instead of reloading the default one. The 0x100 to 0x1FF window of the
image is overwritten with the cartridge header before execution, which is the
gap the 2304 byte layout leaves for it.
source_ref: "Pizza Boy GBC Pro 6.0.6 MainActivity.java:8073-8078 (slot selection),
SettingsActivity.java:98 (preference key), :158-192 (preference and picker),
res/xml/pref_general.xml:97-99; Pizza Boy C Basic 4.1.6 libpizzaboy-jni.so
mmu.c:435-452 (read, header copy, 2304 gate), gameboy.c:1179 (model from the
return value), :1189-1198 (program counter, accumulator, palette)"
+188
View File
@@ -0,0 +1,188 @@
emulator: "Pizza Boy SC"
type: standalone
core_classification: other
source: "https://play.google.com/store/apps/details?id=it.dbtecno.pizzaboyscpro"
upstream: closed-source
author: "Pizza Emulators"
profiled_date: "2026-08-12"
core_version: "1.2.4"
display_name: "Sega - MS/GG/MD/CD (Pizza Boy SC)"
mode: standalone
cores:
- "pizza-boy-sc"
- "Pizza Boy SC"
- "PIZZA-BOY-SC"
- "it.dbtecno.pizzaboyscpro"
- "it.dbtecno.pizzaboyscbasic"
systems:
- sega-mastersystem
- sega-gamegear
- sega-megadrive
- sega-megacd
notes: |
Two Android packages, closed source, sold and given away on Google Play under the
Pizza Boy SC name, reached by ES-DE through its PIZZA-BOY-SC find rule and started
with the game passed as the rom_uri extra: it.dbtecno.pizzaboyscpro, the paid build
the rule names first, and it.dbtecno.pizzaboyscbasic, the free one. The build read
here is Basic 1.2.4 (versionCode 33), a Play distribution drop carrying the source
stamp and signed by the Play App Signing certificate sha256
5ae32245362ccafab6977e759f658dda66bac81cebdd804581cb55db2f219149. The Pro on the
store is 1.4.25 and no genuine copy of it is reachable: apkcombo bounces the
download page of a paid app back to the app page, apkmirror carries no SC build,
archive.org holds none, and the one apkvision copy, labelled Pro 1.3.7, is signed
CN=APKVISION.ORG with no source stamp and was rejected. The Basic library serves
both packages: besides its own entry points it exports
Java_it_dbtecno_pizzaboyscpro_MainActivity_jniEnableCallback.
The core is libsc.so, a Rust tree built as one workspace whose compilation units
are named in its own panic and log records: emulated/systems/genesis,
emulated/systems/sms, emulated/systems/mega_cd, emulated/components/cdrom,
emulated/common and frontend/android. The armeabi-v7a build shipped in the split
is stripped and carries no DWARF, so the file and line of every reference below
comes from the Location records the Rust log and panic paths embed. Four machines
run: engine start compares the system name against SMS, GameGear and SegaCD and
falls through to Genesis (lib.rs:481, 517, 538, 550), which covers Master System
and Mark III, Game Gear, Mega Drive and Genesis, and Mega CD and Sega CD. Discs
are read from cue and chd images through components/cdrom.
Four BIOS slots exist, one per machine, set in one call whose log reads
"jni setBIOSFiles sms: {} gg: {} cd: {} md: {}" (lib.rs:424); a fifth setter stores
a single path in a slot of its own that engine start never reads (lib.rs:416), and
setBIOSBoot logs "TODO jni setBIOSboot" and does nothing. Each branch reads the
slots its machines use, the Master System one reading the Game Gear slot as well,
and an empty slot is an ordinary case for Master System, Game Gear and Mega Drive.
Only the Mega CD slot is mandatory: without it the run stops at "MegaCD Bios not
provided" (lib.rs:564) and engine start returns its failure code.
The Mega CD image is the only file the core examines. It is read and its length
compared with 131072, then handed to the machine, which repeats the same
comparison and panics on a mismatch (megacd_main_machine.rs:156-157). Nothing else
about it is tested: no name, no header, no hash, and no region, the Game Region
setting being passed separately as jap, usa or eu and never selecting a file.
The user supplies each file through the document picker, which filters nothing:
the chosen document is copied into the application temp directory under the name
the picker reports, or, when that name ends in zip, the first entry is extracted
there instead, and the absolute path of the copy is stored. In the free package the
BIOS preferences are declared android:enabled="false" behind a paid badge, and its
Java never hands a path to the core.
Everything else the app opens it makes itself: the default skins, the cheat
descriptors and the two shaders are raw resources unpacked at first run, and the
box art, cheat, layout, sticker and per-ROM databases are created by their own
CREATE TABLE.
files:
- name: bios_CD_U.bin
system: sega-megacd
required: true
agnostic: true
variant_group: "megacd-boot-rom"
size: 131072
validation: [size]
description: "Sega CD boot ROM"
note: >-
Chosen from any location under any name through the document picker, or, when
the picked document is named .zip, taken from its first entry. The stored path
is read at engine start and the byte count compared with 131072; the machine
compares it a second time and panics when it differs. An absent path ends the
run with "MegaCD Bios not provided", an empty one with "MegaCD BIOS path is
missing", a failed read with "Error loading BIOS file", and a wrong length with
"Invalid BIOS len". The core holds one Mega CD slot and applies no other test,
so the boot ROM of any region satisfies it; the three are listed because the
region of the discs decides which one has to be installed.
source_ref: "Pizza Boy SC Basic 1.2.4 libsc.so frontend/android/src/lib.rs:424
(four slot handoff), :517 (SegaCD branch), :564 (absent), :567 (validation
entry), :573 (empty path), :580 (read failure), :592 (length), :596 (accepted);
emulated/systems/mega_cd/src/megacd_main_machine.rs:156-157 (second length test
and panic); SettingsActivity.java:177-219 (picker, zip entry, stored path),
res/xml/pref_general.xml:105-123 (preferences and defaults)"
- name: bios_CD_E.bin
system: sega-megacd
required: true
agnostic: true
variant_group: "megacd-boot-rom"
size: 131072
validation: [size]
description: "Mega CD boot ROM"
note: >-
Same slot, same picker and same length test as the other Mega CD boot ROMs.
source_ref: "Pizza Boy SC Basic 1.2.4 libsc.so frontend/android/src/lib.rs:567-596,
emulated/systems/mega_cd/src/megacd_main_machine.rs:156-157"
- name: bios_CD_J.bin
system: sega-megacd
required: true
agnostic: true
variant_group: "megacd-boot-rom"
size: 131072
validation: [size]
description: "Mega CD boot ROM (Japan)"
note: >-
Same slot, same picker and same length test as the other Mega CD boot ROMs.
source_ref: "Pizza Boy SC Basic 1.2.4 libsc.so frontend/android/src/lib.rs:567-596,
emulated/systems/mega_cd/src/megacd_main_machine.rs:156-157"
- name: bios_U.sms
system: sega-mastersystem
required: false
agnostic: true
variant_group: "mastersystem-boot-rom"
description: "Master System boot ROM"
note: >-
Picked and stored like the Mega CD image and handed to the machine as a path.
Nothing about the file is examined on either side of the bridge, and an empty
slot is not an error: the cartridge runs with the boot sequence skipped.
source_ref: "Pizza Boy SC Basic 1.2.4 libsc.so frontend/android/src/lib.rs:424
(slot), :538 (branch reading the Master System and Game Gear slots),
emulated/systems/sms/src/system.rs:202 (path logged into the machine)"
- name: bios_E.sms
system: sega-mastersystem
required: false
agnostic: true
variant_group: "mastersystem-boot-rom"
description: "Master System boot ROM (Europe)"
note: "Same slot and same absence of tests as the other Master System boot ROMs."
source_ref: "Pizza Boy SC Basic 1.2.4 libsc.so frontend/android/src/lib.rs:538,
emulated/systems/sms/src/system.rs:202"
- name: bios_J.sms
system: sega-mastersystem
required: false
agnostic: true
variant_group: "mastersystem-boot-rom"
description: "Master System boot ROM (Japan)"
note: "Same slot and same absence of tests as the other Master System boot ROMs."
source_ref: "Pizza Boy SC Basic 1.2.4 libsc.so frontend/android/src/lib.rs:538,
emulated/systems/sms/src/system.rs:202"
- name: bios.gg
system: sega-gamegear
required: false
agnostic: true
description: "Game Gear boot ROM"
note: >-
Its own slot, separate from the Master System one, both read on the branch that
serves the two machines. Picked and stored the same way, handed to the machine
as a path, and never examined; an empty slot is not an error.
source_ref: "Pizza Boy SC Basic 1.2.4 libsc.so frontend/android/src/lib.rs:424
(slot), :481 (system name match, GameGear), :538 (branch reading the Master
System and Game Gear slots)"
- name: bios_MD.bin
system: sega-megadrive
required: false
agnostic: true
description: "Mega Drive TMSS boot ROM"
note: >-
Read on the Genesis branch, the one engine start falls through to when the
system name is neither SMS, GameGear nor SegaCD. Picked and stored the same
way and never examined; the machine reports it as "BIOS detected" and runs
without it when the slot is empty.
source_ref: "Pizza Boy SC Basic 1.2.4 libsc.so frontend/android/src/lib.rs:424
(slot), :550 (Genesis branch and slot read),
emulated/systems/genesis/src/system.rs:270 (path logged into the machine),
emulated/systems/genesis/src/genesis_machine.rs:135 (detection)"
+50
View File
@@ -0,0 +1,50 @@
emulator: Plastic
type: standalone
core_classification: other
source: "https://github.com/Amjad50/plastic"
upstream: "https://github.com/Amjad50/plastic"
profiled_date: "2026-08-12"
source_commit: "74152adb3acd890d3abee2ff5906408f26a199e2"
core_version: "0.3.5"
display_name: "Nintendo - NES / Famicom (Plastic)"
cores:
- plastic
systems:
- nintendo-nes
mode: standalone
notes: |
NES emulator written in Rust by Amjad Alsharafi. The emulation lives in the
plastic_core crate and two binaries drive it: plastic, an egui window, and
plastic_tui, a terminal frontend (docs/man/plastic.1). Both take the ROM
path as their first argument (plastic_ui/src/main.rs:418-424,
plastic_tui/src/main.rs:5-38).
A cartridge boots with nothing supplied. The 2A03, the PPU and every mapper
are emulated in software and the console has no boot ROM, so no BIOS or
firmware is read. Cartridge::from_file accepts a path only when its
extension is nes and its first four bytes are the iNES magic
(plastic_core/src/cartridge/mod.rs:184-263, :157-165). get_mapper implements
0, 1, 2, 3, 4, 7, 9, 10, 11, 12 and 66, and any other number returns
MapperNotImplemented (:280-296). No Famicom Disk System path exists and
therefore no disksys.rom.
The NES to RGB table is a constant compiled into the binary
(plastic_core/src/display/color.rs:22-87, selected at :158) and the 32 bytes
at 0x3F00 are the PPU palette RAM (plastic_core/src/ppu2c02/palette.rs:6-19),
so no palette file is opened. The window icon is embedded at build time
(plastic_ui/src/main.rs:430).
The emulator reads back only what it wrote itself. A cartridge whose header
carries the battery bit gets <rom>.nes.sav beside the ROM, written on drop
and reloaded on the next run (plastic_core/src/cartridge/mod.rs:319-348,
:457-463). Save state slots 0 to 9 are <rom-stem>_<slot>.pst under the data
directory, ~/.local/share/plastic/saved_states on Linux
(plastic_ui/src/main.rs:16-32,95-118; plastic_tui/src/ui.rs:38-51,144-176;
plastic_core/src/nes.rs:393-406).
Gamepad support comes from gilrs, which compiles the SDL controller database
into the binary and takes its only override from the SDL_GAMECONTROLLERCONFIG
environment variable rather than a file (gilrs src/mapping/mod.rs:477-485).
files: []
+227
View File
@@ -0,0 +1,227 @@
emulator: project64
type: standalone
core_classification: other
source: "https://github.com/project64/project64"
upstream: "https://github.com/project64/project64"
profiled_date: "2026-08-12"
source_commit: "6188e9a88dd2e7487df346fecc445716654e18ec"
core_version: "Dev-4.0.0"
display_name: "Nintendo - Nintendo 64 (Project64)"
cores:
- project64
systems:
- nintendo-64
- nintendo-64dd
mode: standalone
notes: |
Nintendo 64 and 64DD emulator for Windows. Project64.exe plus the plugin DLLs
the same solution builds, driven by the plugin spec in Source/Project64-plugin-spec.
ES-DE passes the ROM as the only argument. AppVeyor builds Win32 and x64 only;
Source/Android holds no build file.
Cartridge boot reads no file. PostPif is hardcoded true, so Reset seeds the
general purpose registers from the CIC identified in the ROM image, points the
program counter at 0xA4000040 and the boot block is copied into SP DMEM. The
branch that would start at the PIF ROM address is unreachable and the PIF ROM
read in the memory handler is commented out, so neither a PIF ROM nor a CIC ROM
is opened (Source/Project64-core/N64System/N64System.cpp:911-916,
Source/Project64-core/N64System/Mips/Register.cpp:342,371-373,395-535,
Source/Project64-core/N64System/MemoryHandler/PifRamHandler.cpp:26).
The CIC is identified from the boot block. ByteSwapRom normalises the image so
each 32-bit read yields the ROM's big-endian word, then GetCicChipID sums those
words from 0x40 to 0x1000 and matches the total against a table of constants.
Three of them are 64DD IPL images: 0xD2E53EF008 for the Japanese retail chip
8303, 0xD2E53E5DDA for the American retail chip 8501, 0xD2E53EF39F for the
development chip 8401. IsLoadedRomDDIPL is that test
(Source/Project64-core/N64System/N64Rom.cpp:240-273,281-305,500-511).
Aleck64 images are recognised by the same table, through a second sum taken at
0xC00, and get their own boot register seed. No arcade hardware is emulated and
no Aleck64 file is opened
(Source/Project64-core/N64System/N64Rom.cpp:283,310-316,
Source/Project64-core/N64System/Mips/Register.cpp:477-479).
Transfer Pak reads a Game Boy cartridge image and its save from paths the user
sets per game. Both are the user's own cartridge dump, and no Game Boy boot ROM
is involved (Source/Project64-core/N64System/Mips/GBCart.cpp:695-698,744,788,
Source/Project64-core/Settings.cpp:242-243).
The support files under Config ship in the installer and in the nightly package.
CIniFile returns silently when the path does not exist, so each of them degrades
to the defaults registered in AddHandler rather than failing
(Source/Common/IniFile.cpp:493-522, Source/Project64-core/Settings.cpp:134-145).
GLideN64 ships as a bundled plugin, pinned as a submodule at
gonetz/GLideN64 c8ef81c7d9aede9f67f6ed3d3426c90541f9f13e, and brings its own
GLideN64.ini, GLideN64.custom.ini and translations. Project64's own code names
none of them; only Installer.iss and package_zip.cmd copy them
(Source/Installer/Installer.iss:38, Source/Script/package_zip.cmd:42-47).
Generated at runtime, never supplied: Project64.cfg, Project64.rdn,
Project64.cache3, Project64.zcache, Config/Cheats-User, Config/Enhancements-User,
Save, Screenshots, Logs and the texture caches.
files:
# -- 64DD IPL ROMs, user supplied --
- name: "64DD_IPL_v12_JPN.bin"
aliases: ["64DD_IPL.bin", "64DD_IPL_JP.n64", "64dd_ipl_J.bin"]
system: nintendo-64dd
region: [japan]
required: true
validation: [signature]
description: "64DD IPL ROM (Japanese retail)"
note: >
Loaded when the disk image reports Country_Japan. The path is the free text
Disk IPL ROM Path setting, typed or pasted into a plain edit box, so the
code fixes no filename and no directory. SelectAndLoadFileImageIPL tests
that the path exists, warns and returns false if not, and the disk never
starts. The file is accepted on two content checks and nothing else: the
first word must be one of the four image magics, 0x40072780 being the 64DD
one, and the boot block sum must be 0xD2E53EF008. Size is not checked and
no file hash is computed.
source_ref: "Source/Project64-core/Settings.cpp:316, Source/Project64-core/N64System/N64System.cpp:577,599,649-652,673-677,690-704, Source/Project64-core/N64System/N64Rom.cpp:303,479-498,500-511, Source/Project64/UserInterface/Settings/SettingsPage-DiskDrive.cpp:13,18,47,140"
- name: "64DD_IPL_USA.bin"
aliases: ["64DD_IPL_US.n64", "64dd_ipl_U.bin"]
system: nintendo-64dd
region: [north-america]
required: true
validation: [signature]
description: "64DD IPL ROM (American retail)"
note: >
Loaded when the disk image reports Country_NorthAmerica, from the Disk IPL
USA ROM Path setting. Same acceptance path as the Japanese image, matched on
boot block sum 0xD2E53E5DDA. The chip differs from the Japanese one, and
CalculateRomCrc carries a separate seed and a 0xA0000 length for it.
source_ref: "Source/Project64-core/Settings.cpp:317, Source/Project64-core/N64System/N64System.cpp:653-656,673-677, Source/Project64-core/N64System/N64Rom.cpp:305,369-372,500-511, Source/Project64/UserInterface/Settings/SettingsPage-DiskDrive.cpp:14,19,56,142"
- name: "64DD_IPL_DEV.bin"
aliases: ["64DD_IPL_DEV.n64", "64dd_ipl_DEV.bin"]
system: nintendo-64dd
required: true
validation: [signature]
description: "64DD IPL ROM (development)"
note: >
Loaded from the Development 64DD IPL ROM Path setting for disks whose country
byte is unknown, which is what development and prototype disks carry. Matched
on boot block sum 0xD2E53EF39F. When a cartridge and a disk are launched
together and this path is empty, the loader falls back to the Japanese image
and then to the American one, so the development image is only unavoidable
for a development disk on its own.
source_ref: "Source/Project64-core/Settings.cpp:318, Source/Project64-core/N64System/N64System.cpp:657-670,673-677, Source/Project64-core/N64System/N64Rom.cpp:304,377-380,500-511, Source/Project64/UserInterface/Settings/SettingsPage-DiskDrive.cpp:15,20,65,144"
# -- Per game databases shipped in the installer --
- name: "Project64.rdb"
path: "Config/Project64.rdb"
system: nintendo-64
required: false
bundled: true
description: "ROM settings database"
note: >
Sections keyed by the ROM identifier CRC1-CRC2-C:country. Backs the whole
Rdb_ setting family, among them RDRAM size, counter factor, save chip, VI
refresh rate, disk seek timing and the overclock modifier, so it decides how
the machine is configured per game. It also carries the microcode identifier
table. Absent, every lookup falls through to the Defaults section and the
ROM browser lists no known titles.
source_ref: "Source/Project64-core/Settings.cpp:87-88,134-145,151-188, Source/Project64-core/Settings/SettingType/SettingsType-RomDatabase.cpp:63,117, Source/Project64-core/RomList/RomList.cpp:47,52,58-61, Source/Project64-core/N64System/N64Rom.cpp:722,914"
- name: "Video.rdb"
path: "Config/Video.rdb"
system: nintendo-64
required: false
bundled: true
description: "Per game video plugin settings"
note: >
Second ini opened by the ROM database setting type, keyed on the same ROM
identifier, holding the microcode CRCs the ucode detector matches and the per
game video overrides. Without it the plugin asks the user to add an unknown
microcode CRC.
source_ref: "Source/Project64-core/Settings.cpp:89-90, Source/Project64-core/Settings/SettingType/SettingsType-RomDatabase.cpp:64,118"
- name: "Audio.rdb"
path: "Config/Audio.rdb"
system: nintendo-64
required: false
bundled: true
description: "Per game audio plugin settings"
note: >
Third ini opened by the ROM database setting type, same key, carrying the per
game audio overrides such as FPSBuffer, Fixed Audio and Sync Audio.
source_ref: "Source/Project64-core/Settings.cpp:91-92, Source/Project64-core/Settings/SettingType/SettingsType-RomDatabase.cpp:65,119"
- name: "Project64.rdx"
path: "Config/Project64.rdx"
system: nintendo-64
required: false
bundled: true
description: "ROM database extension"
note: >
Extended per game information the ROM browser shows, loaded into the romlist
as m_ExtIniFile alongside the ROM database itself. Absent, the browser
columns it feeds stay empty.
source_ref: "Source/Project64-core/Settings.cpp:103-104, Source/Project64-core/RomList/RomList.cpp:46,51"
- name: "Config/Cheats/*.cht"
system: nintendo-64
required: false
bundled: true
description: "Shipped cheat database"
note: >
Directory scanned for that pattern, one file per game, sections keyed on the
ROM identifier and holding the GameShark style codes. The user directory
Config/Cheats-User is scanned straight after and is where the UI writes.
671 files ship in the installer.
source_ref: "Source/Project64-core/Settings.cpp:93-96, Source/Project64-core/N64System/Enhancement/Enhancements.cpp:629,647, Source/Installer/Installer.iss:29"
- name: "Config/Enhancements/*.enh"
system: nintendo-64
required: false
bundled: true
description: "Shipped enhancement database"
note: >
Directory scanned for that pattern, same per game keying as the cheat files,
holding the patches offered under Enhancements such as widescreen hacks. The
user directory Config/Enhancements-User is scanned straight after. 115 files
ship in the installer.
source_ref: "Source/Project64-core/Settings.cpp:97-100, Source/Project64-core/N64System/Enhancement/Enhancements.cpp:665,684, Source/Installer/Installer.iss:30"
# -- Interface localisation --
- name: "Lang/*.pj.Lang"
system: nintendo-64
required: false
bundled: true
description: "Interface translations"
note: >
Directory scanned for that pattern, each file naming its language in a header
string. English is compiled in through the DEF_STR table, so an empty
directory leaves the interface in English.
source_ref: "Source/Project64-core/Settings.cpp:127-128, Source/Project64-core/Multilanguage/Language.cpp:9-571,656-673, Source/Installer/Installer.iss:33"
# -- Prebuilt plugins with no source in the tree --
- name: "Jabo_Direct3D8.dll"
path: "Plugin/GFX/Jabo_Direct3D8.dll"
system: nintendo-64
required: false
bundled: true
description: "Jabo's Direct3D8 video plugin"
note: >
Committed as a prebuilt binary under Plugin/Win32 and copied by both the
installer and the nightly packager. No source for it exists in the tree, so a
build from source cannot produce it. Project64-Video is the default graphics
plugin, so it is only selected when the user picks it.
source_ref: "Source/Project64-core/Settings.cpp:383, Source/Installer/Installer.iss:36, Source/Script/package_zip.cmd:60"
- name: "Jabo_Dsound.dll"
path: "Plugin/Audio/Jabo_Dsound.dll"
system: nintendo-64
required: false
bundled: true
description: "Jabo's DirectSound audio plugin"
note: >
Committed as a prebuilt binary under Plugin/Win32 and copied by both the
installer and the nightly packager, with no source in the tree.
Project64-Audio is the default audio plugin.
source_ref: "Source/Project64-core/Settings.cpp:385, Source/Installer/Installer.iss:34, Source/Script/package_zip.cmd:58"
+117
View File
@@ -0,0 +1,117 @@
emulator: "Real3DOPlayer"
type: standalone
core_classification: other
source: "http://www.arts-union.ru/node/23"
upstream: closed-source
author: "AltmerSoft (Maxim Grishin)"
profiled_date: "2026-08-12"
core_version: "1.0.32"
display_name: "The 3DO Company - 3DO (Real3DOPlayer)"
mode: standalone
cores:
- "real3doplayer"
- "Real3DOPlayer"
- "REAL3DOPLAYER"
systems:
- 3do
notes: |
Android package ru.vastness.altmer.real3doplayer, closed source, published by the
author of the Phoenix Emulation Project and reached by ES-DE through its
REAL3DOPLAYER find rule. The build read here is app-release.apk of 2019-11-19,
taken from real3DOPlayer_free_1.0.32.zip on the author's own site, carrying the
certificate sha256 336dca7bf758d4d4d3e31783a1cb3f777cf0f0791ff6b1a8bbf698892f8860a9
(C=RU, L=Tula, O=AltmerSoft, CN=MAXIM GRISHIN): versionCode 33, minSdk 14,
targetSdk 23, seven ABIs. Java line numbers below are jadx output of that build and
native addresses are its arm64-v8a library; the armeabi-v7a library carries the same
strings and the same constants. The decompiled tree published as
BoUnCe587/Real3DOPlayer was rejected: it is signed with the AOSP test key
a40da80a59d170caa950cf15c18c454d47a39b26989d8b640ecd745ba71bf5dc.
One system is emulated, 3DO Interactive Multiplayer, in libphoenixcore.so behind a
JNI bridge (NativeCore.java:6-51). The library names itself "PhoenixEmuProject core
2.8.21" and builds the console out of MADAM, CLIO, SPORT, CD-ROM, BIOS, FONT-ROM,
FMV-ROM and NVRAM devices.
The user points the app at one directory holding both the discs and the ROMs, shown
as "Current ISOs and BIOS path". countGames lists it, keeping the extensions bin,
cdi, img, iso, nrg and rom, and offers every file to three adapters in turn: CD
image, then BIOS, then font ROM (0xdd390-0xdd9e0, dispatch at 0xdc43c). An external
launcher can instead pass explicit paths through the intent extras rom, cd and font,
which become the config keys ext-rom, ext-cd and ext-font
(MainActivity.java:469-471,412-414).
Nothing is recognised by name. A ROM candidate is measured, and a file of 3 MB or
more is dropped before it is read; the remainder is scanned on four byte boundaries
for the RomTag signature 01 5A 5A 5A 5A 5A 01 00, and the 0x84 byte header at that
point is read back. The null terminated string at header offset 0x28 is what sorts
the file: "rom" fills the BIOS list, "rom2" the font list, and "fmvrom" is compared
for but never requested (0xaa0e0-0xaa350). Running that scan over the published 3DO
dumps sorts every system BIOS into "rom" and every kanji dump into "rom2", the
512 KB arcade ROM and the 933636 byte FZ-1 font included.
The BIOS is the one file the app refuses to run without: an empty
NativeCore.nameOfBios() raises "BIOS not found." and returns instead of starting the
emulator, and at startup it raises "Select 3DO directory on SD card with BIOS and
CD-images." (MainActivity.java:539-543,583-584). Nothing gates on the font ROM.
The md5 of the loaded BIOS is compared against a48e6746bd7edec0f40cff078f0bb19f, the
Panasonic FZ-10 PAL ANVIL dump, and the outcome is passed as one construction
argument of the device set (0x8eea0-0x8ef58, again at 0x916c0-0x916f4). It selects
behaviour for that dump and is not an acceptance test: acceptance is the RomTag.
Four further md5 constants (5df7f21286290b2b4e9bd939f747f985,
dacffcf51e54e76b68fb62ec73faff42, 0da811a327361f9a3d7dca63ad503f30,
2536bf786f05af221038313a3e28f9aa) are all compared against the md5 taken for the
CD-ROM device, so they identify game discs rather than firmware.
The FMV-ROM device is built but can never be fed: the ROM adapter is only ever
constructed for tags "rom" and "rom2" (0xdc4e8, 0xe9784, 0xe98bc), the frontend
registers only Library/CD-ROM, Library/BIOS and Library/FONT-ROM (0xe965c, 0xe9794,
0xe98cc), and no ext-fmv key exists.
Files the app makes for itself, in its storage directory rather than the scan
directory: nvram.bin, the 32 KB console save area, erasable from the interface;
configs.xml and settings.ini; save states; and the controller maps. madam.bin and
clio.bin name 2 KB and 64 KB regions of the emulator's own state blob and are
reached only in mode 2 (0x8ce8c-0x8d064).
files:
- name: panafz10e-anvil.bin
system: 3do
required: true
agnostic: true
max_size: 3145727
validation: [size]
config_key: "ext-rom"
description: "3DO system BIOS ROM"
note: >-
Any 3DO system ROM is accepted, under any name and from any directory the user
picks. The file is measured, then searched on four byte boundaries for the
RomTag signature, and it is taken as the BIOS when the header names itself
"rom". A file of 3 MB or more is rejected unread. The emulator will not start
until one is found, and the interface lists it above the discs.
source_ref: "Real3DOPlayer 1.0.32 MainActivity.java:100-101 (scan and BIOS name),
MainActivity.java:539-543,583-584 (refusal without it), MainActivity.java:412,469
(ext-rom), libphoenixcore.so arm64-v8a 0xaa0e0-0xaa118 (size gate),
0xaa140-0xaa1b0 (RomTag scan and header read), 0xaa218-0xaa27c (\"rom\" test),
0xdc43c-0xdc53c (dispatch and list), 0xdd228-0xdd2e0 (nameOfBios),
0xdd390-0xdd908 (directory scan and extensions), 0x8f6f0-0x8f71c (1 MB window)"
- name: panafz1j-kanji.bin
system: 3do
required: false
agnostic: true
max_size: 3145727
validation: [size]
config_key: "ext-font"
description: "3DO kanji font ROM"
note: >-
Found by the same scan of the same directory, and taken as the font when the
RomTag header names itself "rom2". Held in its own list and mapped into a second
1 MB window of the machine. Japanese titles draw their kanji from it; the
emulator starts and runs without one, and the core carries GRAFERR_NO_FONT and
GRAFERR_BADFONTFILE for that case.
source_ref: "Real3DOPlayer 1.0.32 MainActivity.java:413,471 (ext-font),
libphoenixcore.so arm64-v8a 0xaa2e8-0xaa34c (\"rom2\" test),
0xdc4d0-0xdc52c (dispatch and list), 0xdd9dc-0xdd9e0 (third scan pass),
0xe98bc-0xe98cc (Library/FONT-ROM), 0x8f74c-0x8f780 (1 MB window)"
+219
View File
@@ -0,0 +1,219 @@
emulator: "Saturn.emu"
type: standalone
core_classification: community_fork
source: "https://github.com/Rakashazi/emu-ex-plus-alpha"
upstream: "https://mednafen.github.io/"
profiled_date: "2026-08-12"
source_commit: "1c12fac5ce49badaadff2e2f210dcc30b89f4943"
core_version: "1.5.85"
display_name: "Sega - Saturn (Saturn.emu)"
mode: standalone
cores:
- "saturn-emu"
- "Saturn.emu"
- "SATURN-EMU"
- "saturnemu"
systems:
- sega-saturn
notes: |
Member of the EX Emulator series by Robert Broglia, published as
com.explusalpha.SaturnEmu and built for arm64 and x86_64 only
(Saturn.emu/metadata/conf.mk:2-7, Saturn.emu/config.mk:7-9). ES-DE reaches it
through the SATURN-EMU find rule, which only the Android rule set carries, and
offers it under both the saturn and saturnjp systems. Mednafen's Saturn module
is vendored under Saturn.emu/src/ss on the 1.32 line
(EmuFramework/include/shared/mednafen/mednafen-config.h:167) and driven by the
app's own video, audio, input and save layers
(Saturn.emu/src/CMakeLists.txt:6-40). Seventeen files differ from the Mednafen
1.32.1 release, none of it touching file loading: statics become externals the
app reads (Saturn.emu/src/ss/ss.cpp:146, Saturn.emu/src/ss/smpc.cpp:96,146,
Saturn.emu/src/ss/vdp2.cpp:46,63, Saturn.emu/src/ss/cdb.cpp:535), backup memory
moves to the app's file objects and the periodic save timers are dropped
(Saturn.emu/src/ss/ss.cpp:1836-1849, mednafen 1.32.1 src/ss/ss.cpp:927-970,
1592-1600,1867-1874), the VDP2 work queue becomes a framework ring buffer
(Saturn.emu/src/ss/vdp2_render.cpp:3211-3231), and the rest is enum and virtual
qualifier tidying. The BIOS and cart ROM block is byte-identical to the release,
as are cart.cpp, cart/rom.cpp and db.cpp.
Content is read from .cue, .ccd, .chd, .toc and .m3u files
(Saturn.emu/metadata/conf.mk:5, Saturn.emu/src/main/system.ccm:106-109). An
archive is opened by the app, which prefers an .m3u member and otherwise keeps
the first entry passing that filter, and an .m3u names up to 16 images
(Saturn.emu/src/main/Main.cc:186-246). Every load goes through the module's
LoadCD entry point (Saturn.emu/src/main/Main.cc:275,
Saturn.emu/src/ss/ss.cpp:1757-1806). The ROM entry point Load is never called:
its only call site in the tree is a shared helper this app does not use
(EmuFramework/src/shared/mednafen-emuex/MDFNUtils.hh:133-146).
Four files the user supplies carry no name of their own. Pickers store
arbitrary URIs under NA/EU BIOS, JP BIOS, KoF '95 ROM and Ultraman ROM, each
filtered to names ending in .bin and each refusing to descend into archives
(Saturn.emu/src/main/EmuMenuViews.cc:34-37,44-145,
EmuFramework/include/emuframework/DataPathSelectView.hh:77-102,
Saturn.emu/src/main/system.ccm:85-95,128-131,
Saturn.emu/src/main/options.cc:65-68,98-101). MDFN_GetSettingS answers the four
path settings with the fixed tokens jp, na, kof95 and ultraman, and
MDFN_MakeFName turns each token back into the matching URI, ending the load
with a message pointing at the File Paths menu when it is unset
(Saturn.emu/src/main/options.cc:215-228,245-285). Every other setting name
reaches unreachable(), so no other firmware request can be made.
Which BIOS is read follows the emulated area: Japan and Asia NTSC take the JP
path, every other area the NA/EU path (Saturn.emu/src/ss/ss.cpp:1388-1394). The
area comes from the Region menu, or when that is Auto from the first 16 sectors
of the disc, checked against the security code hash and the "SEGA SEGASATURN "
magic (Saturn.emu/src/main/EmuMenuViews.cc:216-251,
Saturn.emu/src/main/options.cc:203-204, Saturn.emu/src/ss/ss.cpp:959-968,
1126-1144,1778-1787). The image is rejected at any length other than 524288 and
then hashed (Saturn.emu/src/ss/ss.cpp:1400-1404). With ss.bios_sanity forced on
(Saturn.emu/src/main/options.cc:193-194) a table of five known images drives two
further tests: a file whose name is one of the five must hash to that entry, and
a file whose hash is one of the five must belong to the area being emulated
(Saturn.emu/src/ss/ss.cpp:1406-1439). An image outside the table passes both,
since each test only rejects on a match. A third test compares Saturn against
ST-V images and can never fire here.
Cart type comes from the Cart Type menu when it is not Auto, otherwise from the
internal game database, otherwise none
(Saturn.emu/src/main/EmuMenuViews.cc:180-214,
Saturn.emu/src/main/options.cc:161-164, Saturn.emu/src/ss/ss.cpp:1761-1790).
The database forces the KoF '95 cart for MK-81088 and T-3101G and the Ultraman
cart for T-13308G, marking all three a game requirement
(Saturn.emu/src/ss/db.cpp:93-96,403), so those three discs read a ROM image and
every other disc reads none.
ST-V, the bootable ROM cart and Action Replay 4M Plus are compiled and
unreachable. All three exist only behind cart types the Cart Type menu does not
list and the database never assigns, and the first two are entered from Load
alone (Saturn.emu/src/ss/ss.cpp:1630,1669, Saturn.emu/src/ss/cart.cpp:166-181).
Their paths would ask for ss.bios_stv_jp, ss.bios_stv_na, ss.bios_stv_eu and
ss.cart.satar4mp_path, none of which MDFN_GetSettingS answers
(Saturn.emu/src/ss/ss.cpp:1379-1387,1293,
Saturn.emu/src/main/options.cc:215-228). The ST-V EEPROM save file and the
ST-V branches in the app's own backup memory code are dead for the same reason
(Saturn.emu/src/main/Main.cc:119-123,141-142).
Per content the app writes and reads back a .bkr backup RAM image, a .smpc real
time clock block, .mca save states and, when a memory cart is selected, a
gzipped .bcr cart image; settings live in SaturnEmu.config
(Saturn.emu/src/main/Main.cc:50-129,152-155,
Saturn.emu/src/main/system.ccm:180, Saturn.emu/src/ss/cart/backup.cpp:69-73,
Saturn.emu/src/main/AppMeta.cc:28). Mednafen's image reader picks up an .sbi
beside a cue sheet when one is present
(EmuFramework/src/shared/mednafen/cdrom/CDAccess_Image.cpp:924-941). Cheats are
off (Saturn.emu/src/main/options.cc:187-188), and ui.png, gpOverlay.png and the
shader sources are drawn from the application bundle
(EmuFramework/include/emuframework/AssetManager.hh:61-66,
EmuFramework/src/AssetManager.cc:63-69,
EmuFramework/src/VideoImageEffect.cc:163-173).
files:
- name: "sega_101.bin"
system: sega-saturn
description: "Saturn BIOS v1.01, read for Japan and Asia NTSC"
required: true
region: [japan, asia-ntsc]
size: 524288
sha256: "dcfef4b99605f872b6c3b6d05c045385cdea3d1b702906a0ed930df7bcb7deac"
validation: [existence, size, sha256]
config_key: "CFGKEY_JP_BIOS_PATH"
category: bios
note: >
The image the module's own setting table names for the JP path
(Saturn.emu/src/ss/ss.cpp:2398), and one of three the sanity table accepts
for Japan and Asia NTSC. Any 524288-byte image the user picks loads unless
the sanity table contradicts it, but a file carrying this name must carry
this hash.
source_ref: "Saturn.emu/src/ss/ss.cpp:1388-1394 (area picks the JP path), Saturn.emu/src/ss/ss.cpp:1396-1404 (open, size, hash), Saturn.emu/src/ss/ss.cpp:1418 (name, hash, areas), Saturn.emu/src/ss/ss.cpp:2398 (setting default), Saturn.emu/src/main/options.cc:218-219,276-281 (token and path), Saturn.emu/src/main/EmuMenuViews.cc:67-88 (picker)"
- name: "mpr-17933.bin"
system: sega-saturn
description: "Saturn BIOS read for every area outside Japan and Asia NTSC"
required: true
region: [north-america, europe, south-korea, asia-pal, brazil, latin-america]
size: 524288
sha256: "96e106f740ab448cf89f0dd49dfbac7fe5391cb6bd6e14ad5e3061c13330266f"
validation: [existence, size, sha256]
config_key: "CFGKEY_NA_BIOS_PATH"
category: bios
note: >
The image the module's own setting table names for the NA/EU path
(Saturn.emu/src/ss/ss.cpp:2399). The sanity table grants it every area
except Japan and Asia NTSC, which covers North America, Europe, South
Korea, Asia PAL, Brazil and Latin America as the Region menu names them.
source_ref: "Saturn.emu/src/ss/ss.cpp:1388-1394 (area picks the NA/EU path), Saturn.emu/src/ss/ss.cpp:1396-1404 (open, size, hash), Saturn.emu/src/ss/ss.cpp:1420 (name, hash, areas), Saturn.emu/src/ss/ss.cpp:2399 (setting default), Saturn.emu/src/main/options.cc:220-221,270-275 (token and path), Saturn.emu/src/main/EmuMenuViews.cc:44-65 (picker), Saturn.emu/src/main/EmuMenuViews.cc:162-176 (area names)"
- name: "sega_100.bin"
system: sega-saturn
description: "Saturn BIOS v1.00, accepted for Japan and Asia NTSC"
required: false
region: [japan, asia-ntsc]
size: 524288
sha256: "ae4058627bb5db9be6d8d83c6be95a4aa981acc8a89042e517e73317886c8bc2"
validation: [existence, size, sha256]
config_key: "CFGKEY_JP_BIOS_PATH"
category: bios
note: >
Interchangeable with the other two Japan images: the sanity table gives all
three the same areas, and nothing in the module ranks them.
source_ref: "Saturn.emu/src/ss/ss.cpp:1417 (name, hash, areas), Saturn.emu/src/ss/ss.cpp:1396-1439 (open, size, hash, sanity tests)"
- name: "sega1003.bin"
system: sega-saturn
description: "Saturn BIOS v1.003, accepted for Japan and Asia NTSC"
required: false
region: [japan, asia-ntsc]
size: 524288
sha256: "cc1e1b7f88f1c6e6fc35994bae2c2292e06fdae258c79eb26a1f1391e72914a8"
validation: [existence, size, sha256]
config_key: "CFGKEY_JP_BIOS_PATH"
category: bios
source_ref: "Saturn.emu/src/ss/ss.cpp:1416 (name, hash, areas), Saturn.emu/src/ss/ss.cpp:1396-1439 (open, size, hash, sanity tests)"
- name: "sega_100a.bin"
system: sega-saturn
description: "Saturn BIOS v1.00a, accepted for every area outside Japan and Asia NTSC"
required: false
region: [north-america, europe, south-korea, asia-pal, brazil, latin-america]
size: 524288
sha256: "87293093fad802fcff31fcab427a16caff1acbc5184899b8383b360fd58efb73"
validation: [existence, size, sha256]
config_key: "CFGKEY_NA_BIOS_PATH"
category: bios
source_ref: "Saturn.emu/src/ss/ss.cpp:1419 (name, hash, areas), Saturn.emu/src/ss/ss.cpp:1396-1439 (open, size, hash, sanity tests)"
- name: "mpr-18811-mx.ic1"
system: sega-saturn
description: "King of Fighters '95 ROM cart"
required: false
agnostic: true
min_size: 2097152
validation: [existence, size]
config_key: "CFGKEY_KOF_ROM_PATH"
category: bios
note: >
Read when the cart type is KoF '95, which the internal database forces for
MK-81088 and T-3101G and which the Cart Type menu also offers. Those two
discs end the load when the path is unset; every other disc ignores it.
CART_ROM_Init takes a fixed 2097152 bytes and Stream::read throws on a
shorter file, so anything smaller aborts and anything larger has its tail
ignored. The name comes from the module's setting table, which this build
never reads: settings.cpp is out of the shared source list, and the picker
lists names ending in .bin.
source_ref: "Saturn.emu/src/ss/ss.cpp:1291 (cart to setting), Saturn.emu/src/ss/ss.cpp:1348-1357 (firmware path, open, hand to CART_Init), Saturn.emu/src/ss/cart.cpp:162-164 (dispatch), Saturn.emu/src/ss/cart/rom.cpp:37-47 (fixed read), Saturn.emu/src/ss/db.cpp:94-95,403 (database forces the cart), Saturn.emu/src/ss/ss.cpp:2434 (setting default), Saturn.emu/src/main/options.cc:222-223,258-263 (token and path), Saturn.emu/src/main/EmuMenuViews.cc:90-111 (picker)"
- name: "mpr-19367-mx.ic1"
system: sega-saturn
description: "Ultraman - Hikari no Kyojin Densetsu ROM cart"
required: false
agnostic: true
min_size: 2097152
validation: [existence, size]
config_key: "CFGKEY_ULTRAMAN_ROM_PATH"
category: bios
note: >
Read when the cart type is Ultraman, which the internal database forces for
T-13308G and which the Cart Type menu also offers. Same fixed 2097152-byte
read as the other ROM cart, and the same picker filtered to .bin.
source_ref: "Saturn.emu/src/ss/ss.cpp:1292 (cart to setting), Saturn.emu/src/ss/ss.cpp:1348-1357 (firmware path, open, hand to CART_Init), Saturn.emu/src/ss/cart.cpp:163-164 (dispatch), Saturn.emu/src/ss/cart/rom.cpp:37-47 (fixed read), Saturn.emu/src/ss/db.cpp:96,403 (database forces the cart), Saturn.emu/src/ss/ss.cpp:2435 (setting default), Saturn.emu/src/main/options.cc:224-225,264-269 (token and path), Saturn.emu/src/main/EmuMenuViews.cc:113-134 (picker)"
+139
View File
@@ -0,0 +1,139 @@
emulator: sixtyforce
type: standalone
core_classification: embedded_hle
source: "https://sixtyforce.com/"
upstream: "https://sixtyforce.com/"
profiled_date: "2026-08-12"
core_version: "2.0.2"
display_name: "Nintendo - Nintendo 64 (sixtyforce)"
cores:
- sixtyforce
systems:
- nintendo-64
- nintendo-64dd
mode: standalone
notes: |
Nintendo 64 emulator for macOS by Gerrit Goossen, closed source since its first
release in 2001. ES-DE runs it from
/Applications/sixtyforce.app/Contents/MacOS/sixtyforce and passes the ROM path.
Everything below is read from the distributed 2.0.2 build (CFBundleVersion 87,
single x86_64 slice, macOS 10.9 or later); addresses are the virtual addresses
of Contents/MacOS/sixtyforce. None of it appears on the site, in the help pages
or in the release notes.
The boot chain reads nothing. There is no PIF ROM and no CIC image: the boot
writes the constants for the CIC itself, dispatching on a number in the 6101 to
7106 range kept in the machine state (0x100071dbf-0x100071e2c). That number is
what Overrides.plist gives for the game, and when the table has no entry the
code sums the ROM's own IPL3 region instead (0x100071c78-0x100071c8f,
0x100071e31-0x100071e94). The country code byte of the cartridge header takes
the PAL branch for D, F, I, P, S, U, X and Y (0x100071d84-0x100071da3).
Every primitive the binary can open a file with (URLForResource:withExtension:,
initWithContentsOfURL:options:error:, initWithFileURL:,
fileHandleForReadingFromURL:error:, the two directory enumerators, mmap)
resolves to three sources: the ROM the user picks, the five bundle resources
below, and the app's own saves.
A ROM is read in any of three byte orders. The first word decides:
0x80371240, 0x80371241 and the 64DD IPL word 0x80270740 are big endian and get
a 32 bit reversal, 0x37804012, 0x37804112 and 0x27804007 are word swapped and
get a 16 bit reversal, 0x40123780, 0x41123780 and 0x40072780 are already in the
internal little endian word order and pass through. A gzip stream or a 60gz
container is decompressed first, and the length has to be a multiple of four
(0x1000ad5c0-0x1000ad6ce, SFGZFile at 0x1000ae2d0). Anything else fails with
"Error Loading Cartridge Format".
64DD support stops at the IPL image. HardwareState carries a cartridge slot
(pointer at +0x120, length at +0x128) and an IPL slot (+0x138, +0x140) and no
disk slot; the document types are n64, v64 and z64, and the only occurrences of
the letters ndd in the whole binary are the two NDDJ immediates in the loader.
Loading the IPL while a cartridge is open leaves the cartridge in place.
Autosaves, game freezes, controller paks and the controller configuration are
written by the app, so none of them is an entry here.
files:
- name: 64DD_IPL.bin
system: nintendo-64dd
required: false
description: "64DD IPL ROM"
note: >
Opened through the file panel like a cartridge. The loader builds the four
byte game code from the header, media format at 0x3b, then the two
cartridge id bytes read 0x3d before 0x3c, then country at 0x3e, and keeps
the image in the 64DD slot instead of the cartridge slot when that code
reads NDDJ. That is the Japanese retail IPL; the USA image reads NDDE and
the development image NDXJ, so neither can reach that slot. No code path
opens the file by name, so the entry carries no
alias and the name is a label. The image is mapped at 0x06000000 and read
back by PI DMA bounded by its own length, and the 64DD register window at
0x05000000, 0x524 bytes for the ASIC buffers and registers, is installed
only once the image is loaded. The same pointer and length decide the disk
drive flag the booting game reads, so an absent image is a supported state.
Nothing checks a hash, and nothing checks a size beyond the container
format and the multiple of four.
source_ref: "sixtyforce 2.0.2 MacOS/sixtyforce 0x100026b18-0x100026b64 (game code test, 64DD slot), 0x10006e470-0x10006e4a7 (game code), 0x100081942-0x1000819b1 (memory map), 0x1000831b2-0x100083285 (PI DMA), 0x100071d62-0x100071d7d (drive flag)"
- name: Overrides.plist
path: "Contents/Resources/Overrides.plist"
system: nintendo-64
required: false
bundled: true
size: 12855
description: "Per-game hardware overrides"
note: >
561 entries keyed by the four byte game code, read at cartridge load and
carrying the CIC seed, the cartridge memory type, the framebuffer flags and
the expanded memory and timing settings. The CIC a game boots with comes
from this table, and the code falls back to a checksum of the ROM when the
table has no entry for it.
source_ref: "sixtyforce 2.0.2 MacOS/sixtyforce 0x100039336 (resource name), 0x1000392d0-0x1000393fa (lookup by game code, CIC key), 0x100026e67-0x100026e89 (called with the game code), 0x100071c78-0x100071c8f (CIC read at boot), 0x1000d21a0 (expanded memory log)"
- name: Controller-Devices.plist
path: "Contents/Resources/Controller-Devices.plist"
required: false
bundled: true
size: 73988
description: "Controller device database"
note: >
The bundle carries one device list. SFControllerManager loads a bundle
property list while it initialises and keeps it in its supportedDevices
table, which the handlers read when a HID device arrives or leaves. The
user's own mappings are a separate file the manager reads and writes from
the application support folder.
source_ref: "sixtyforce 2.0.2 MacOS/sixtyforce 0x100013494-0x1000134e6 (bundle load into supportedDevices), 0x10001918e (read on device arrival), 0x100013870-0x100013a87 (user mappings, separate read)"
- name: HID-Usage-Names.plist
path: "Contents/Resources/HID-Usage-Names.plist"
required: false
bundled: true
size: 28249
description: "HID usage names"
note: >
Read from the bundle to name the HID usages and usage pages shown while
mapping a controller element.
source_ref: "sixtyforce 2.0.2 MacOS/sixtyforce 0x10001cc6d-0x10001cc81 (resource name and load)"
- name: Key-Names.plist
path: "Contents/Resources/Base.lproj/Key-Names.plist"
required: false
bundled: true
size: 2440
description: "Keyboard key names"
note: >
Localised key names for the keyboard controller configuration sheet, read
from the bundle through the same loader as the other property lists.
source_ref: "sixtyforce 2.0.2 MacOS/sixtyforce 0x100010c8d-0x100010ca1 (resource name and load)"
- name: Unit.data
path: "Contents/Resources/Unit.data"
required: false
bundled: true
size: 65536
description: "Display texture"
note: >
Read from the bundle while the video controller sets up its OpenGL context
and kept as the unitTexture the controller draws with.
source_ref: "sixtyforce 2.0.2 MacOS/sixtyforce 0x10004245b-0x10004247b (resource name and load), 0x10004686d (called from video setup), 0x10004658a (unitTexture use)"
+259
View File
@@ -0,0 +1,259 @@
emulator: Skyline
type: standalone
core_classification: other
source: "https://github.com/skyline-emu/skyline"
upstream: "https://github.com/skyline-emu/skyline"
profiled_date: "2026-08-12"
source_commit: "dc20a615275f66bee20a4fd851ef0231daca4f14"
core_version: "0.0.3"
display_name: "Nintendo - Switch (Skyline)"
cores:
- "skyline"
- "SKYLINE"
systems:
- nintendo-switch
mode: standalone
notes: |
Nintendo Switch emulator for ARMv8 Android, written from scratch in C++ and Kotlin.
Android package skyline.emu, versionCode 3, minSdk 29, with the debug variant taking a
.dev suffix (build.gradle:23,28-29,120-121). ES-DE reaches it through its SKYLINE find
rule and starts it with android.intent.action.VIEW on the content URI of the game.
Development ceased and the README at the pinned commit records it; the code is split
across skyline and skyline-dev, whose external file surface is identical (key_store.cpp
:10-13 and shared_font_core.h:40-47 in both).
NCA, NRO, NSO, NSP and XCI are loaded (loader/). Two key files are read, from keys/
under the application internal files directory, which os.cpp:35 hands to the key store
as its root. Both arrive through the in-app importer, which accepts only the two names
and rewrites the trimmed pairs into that directory (KeyReader.kt:25-26,56-60); nothing
else is consulted for keys, and there is no dev.keys or console.keys path.
No firmware is installed and none is read. The system version is answered from a
hardcoded 9.0.0-4.0 structure (ISystemSettingsServer.cpp:9-10) and the system data
archives a game asks for through OpenDataStorageByDataId are served as stub RomFS
images from the application assets (IFileSystemProxy.cpp:84-90). Two are carried:
0100000000000806, the NgWord filter, holding 0.txt through 15.txt plus common.txt and
version.dat, and 0100000000000823, NgWord2, holding ac_<0-15>_b1_nx, ac_<0-15>_b2_nx
and ac_<0-15>_not_b_nx. A data id without a matching asset opens nothing.
The six shared fonts are the one place where a firmware file replaces a built-in one.
Each is looked for in fonts/ under the application external files directory, which
resolves to /storage/emulated/0/Android/data/skyline.emu/files/ (SkylineApplication.kt
:19,41), and only when it is absent does the asset of the same name serve instead
(shared_font_core.h:40-47). The emulator writes the shared font header itself, a magic
followed by the length XORed with a key derived at shared_font_core.h:36-38, and then
copies the whole file after it (shared_font_core.h:51-55), so the file it expects is
the raw TTF payload rather than the headered form the firmware stores. Sizes are taken
from the file and never checked, and the six together have to fit the 0x140A000 shared
memory block.
A custom Vulkan driver can be loaded through adrenotools from gpu_drivers/<label>/
under the internal files directory (gpu.cpp:342-357). The label and the library
filename are both read from a meta.json inside the archive the user installs
(GpuDriverHelper.kt:19-22,150-191,219), so the code names no driver file of its own;
loading falls back to the built-in driver and then to the system libvulkan.so. Save
data and the emulated SD card live under switch/ in the external files directory
(IFileSystemProxy.cpp:21,67) and are written by the emulator.
files:
- name: prod.keys
path: "keys/prod.keys"
system: nintendo-switch
required: true
description: "Production keys for content decryption"
note: >-
Read as name=value pairs from keys/ under the application internal files directory.
Supplies header_key, and the titlekek_XX, key_area_key_application_XX,
key_area_key_ocean_XX and key_area_key_system_XX generation-indexed sets. An
encrypted NCA without header_key fails with MissingHeaderKey, and one whose key
area cannot be unwrapped fails with MissingKeyArea, so no retail title loads
without this file. The importer accepts a pair only when the name contains an
underscore and the value is hexadecimal.
source_ref: "app/src/main/cpp/skyline/os.cpp:35 (root directory), app/src/main/cpp/skyline/crypto/key_store.cpp:12-13 (read), app/src/main/cpp/skyline/crypto/key_store.h:30-39 (key names), app/src/main/cpp/skyline/crypto/key_store.cpp:46-62 (parse), app/src/main/cpp/skyline/vfs/nca.cpp:21-22,126 (failures), app/src/main/java/emu/skyline/KeyReader.kt:83-88 (import check)"
- name: title.keys
path: "keys/title.keys"
system: nintendo-switch
required: false
description: "Per-title keys"
note: >-
Read as rights id to title key pairs from the same directory. A title key normally
arrives instead from the .tik tickets carried inside an NSP, which are parsed and
pushed into the same store, so this file is only needed when no ticket supplies
one; that case fails with MissingTitleKey. The importer requires both halves of a
pair to be 32 hexadecimal characters.
source_ref: "app/src/main/cpp/skyline/crypto/key_store.cpp:10-11 (read), app/src/main/cpp/skyline/crypto/key_store.cpp:35-39 (parse), app/src/main/cpp/skyline/loader/nsp.cpp:14-21 (tickets), app/src/main/cpp/skyline/vfs/nca.cpp:108-110 (failure), app/src/main/java/emu/skyline/KeyReader.kt:77-82 (import check)"
- name: FontStandard.ttf
path: "fonts/FontStandard.ttf"
system: nintendo-switch
required: false
has_builtin: true
description: "Shared font, standard"
note: >-
Loaded from fonts/ under the application external files directory when present,
otherwise from the asset of the same name, which carries Noto Sans CJK. Copied
into the shared font block behind a header the emulator generates, so the expected
content is the raw TTF payload.
source_ref: "app/src/main/cpp/skyline/services/pl/shared_font_core.h:26 (entry), :40-47 (lookup and fallback), :51-55 (header and copy)"
- name: FontChineseSimplified.ttf
path: "fonts/FontChineseSimplified.ttf"
system: nintendo-switch
required: false
has_builtin: true
description: "Shared font, simplified Chinese"
note: >-
Same lookup as the standard font, with a Noto Sans CJK asset behind it.
source_ref: "app/src/main/cpp/skyline/services/pl/shared_font_core.h:27 (entry), :40-47 (lookup and fallback), :51-55 (header and copy)"
- name: FontExtendedChineseSimplified.ttf
path: "fonts/FontExtendedChineseSimplified.ttf"
system: nintendo-switch
required: false
has_builtin: true
description: "Shared font, extended simplified Chinese"
note: >-
Same lookup as the standard font, with a Noto Sans CJK asset behind it.
source_ref: "app/src/main/cpp/skyline/services/pl/shared_font_core.h:28 (entry), :40-47 (lookup and fallback), :51-55 (header and copy)"
- name: FontChineseTraditional.ttf
path: "fonts/FontChineseTraditional.ttf"
system: nintendo-switch
required: false
has_builtin: true
description: "Shared font, traditional Chinese"
note: >-
Same lookup as the standard font, with a Noto Sans CJK asset behind it.
source_ref: "app/src/main/cpp/skyline/services/pl/shared_font_core.h:29 (entry), :40-47 (lookup and fallback), :51-55 (header and copy)"
- name: FontKorean.ttf
path: "fonts/FontKorean.ttf"
system: nintendo-switch
required: false
has_builtin: true
description: "Shared font, Korean"
note: >-
Same lookup as the standard font, with a Noto Sans CJK asset behind it.
source_ref: "app/src/main/cpp/skyline/services/pl/shared_font_core.h:30 (entry), :40-47 (lookup and fallback), :51-55 (header and copy)"
- name: FontNintendoExtended.ttf
path: "fonts/FontNintendoExtended.ttf"
system: nintendo-switch
required: false
has_builtin: true
description: "Shared font, extended button glyphs"
note: >-
Same lookup as the standard font, with a Roboto asset behind it.
source_ref: "app/src/main/cpp/skyline/services/pl/shared_font_core.h:31 (entry), :40-47 (lookup and fallback), :51-55 (header and copy)"
- name: "0100000000000806"
path: "romfs/0100000000000806"
system: nintendo-switch
required: false
bundled: true
unsourceable: "stub image the emulator build carries inside its package, not a dump of the system data archive it stands in for"
description: "NgWord system data archive"
note: >-
Stub RomFS image served from the application assets when a game opens the data
storage for this title id. Holds 0.txt through 15.txt, common.txt and version.dat.
source_ref: "app/src/main/cpp/skyline/services/fssrv/IFileSystemProxy.cpp:84-90"
- name: "0100000000000823"
path: "romfs/0100000000000823"
system: nintendo-switch
required: false
bundled: true
unsourceable: "stub image the emulator build carries inside its package, not a dump of the system data archive it stands in for"
description: "NgWord2 system data archive"
note: >-
Stub RomFS image served from the application assets when a game opens the data
storage for this title id. Holds ac_<0-15>_b1_nx, ac_<0-15>_b2_nx and
ac_<0-15>_not_b_nx.
source_ref: "app/src/main/cpp/skyline/services/fssrv/IFileSystemProxy.cpp:84-90"
- name: binaryList.txt
path: "tzdata/binaryList.txt"
system: nintendo-switch
required: false
bundled: true
unsourceable: "generated by the emulator build from the public time zone database and carried inside its package"
description: "Time zone location list"
note: >-
Read from the application assets at time service init and used as the list of
known locations. It names the 594 zone binaries under tzdata/zoneinfo/, each of
which is opened by location name when a zone rule is loaded. The set is generated
from tzdb 2021a in Horizon format.
source_ref: "app/src/main/cpp/skyline/services/timesrv/core.cpp:272 (list), :293 (zone binary by name), app/src/main/cpp/skyline/services/glue/ITimeZoneService.cpp:29,56 (zone binary by requested location)"
- name: version.txt
path: "tzdata/version.txt"
system: nintendo-switch
required: false
bundled: true
unsourceable: "generated by the emulator build from the public time zone database and carried inside its package"
description: "Time zone data version"
note: >-
Read from the application assets at time service init and reported as the time
zone binary version.
source_ref: "app/src/main/cpp/skyline/services/timesrv/core.cpp:289"
- name: profile_picture.jpeg
system: nintendo-switch
required: false
bundled: true
unsourceable: "placeholder image carried inside the emulator package"
description: "Default user profile image"
note: >-
Opened from the application assets when a game asks the account service for the
profile image of the emulated user.
source_ref: "app/src/main/cpp/skyline/services/account/IProfile.cpp:66"
- name: blit.vert.spv
path: "shaders/blit.vert.spv"
system: nintendo-switch
required: false
bundled: true
unsourceable: "build output of the emulator's own shader source, carried inside its package"
description: "Blit vertex helper shader"
note: >-
Opened from the application assets when the GPU helper shaders are built. Compiled
at build time from app/src/main/shaders/blit.vert.
source_ref: "app/src/main/cpp/skyline/gpu/shaders/helper_shaders.cpp:201, app/src/main/cpp/skyline/gpu.cpp:403 (asset filesystem)"
- name: blit.frag.spv
path: "shaders/blit.frag.spv"
system: nintendo-switch
required: false
bundled: true
unsourceable: "build output of the emulator's own shader source, carried inside its package"
description: "Blit fragment helper shader"
note: >-
Opened from the application assets when the GPU helper shaders are built. Compiled
at build time from app/src/main/shaders/blit.frag.
source_ref: "app/src/main/cpp/skyline/gpu/shaders/helper_shaders.cpp:201, app/src/main/cpp/skyline/gpu.cpp:403 (asset filesystem)"
- name: clear.vert.spv
path: "shaders/clear.vert.spv"
system: nintendo-switch
required: false
bundled: true
unsourceable: "build output of the emulator's own shader source, carried inside its package"
description: "Clear vertex helper shader"
note: >-
Opened from the application assets when the GPU helper shaders are built. Compiled
at build time from app/src/main/shaders/clear.vert.
source_ref: "app/src/main/cpp/skyline/gpu/shaders/helper_shaders.cpp:328, app/src/main/cpp/skyline/gpu.cpp:403 (asset filesystem)"
- name: clear.frag.spv
path: "shaders/clear.frag.spv"
system: nintendo-switch
required: false
bundled: true
unsourceable: "build output of the emulator's own shader source, carried inside its package"
description: "Clear fragment helper shader"
note: >-
Opened from the application assets when the GPU helper shaders are built. Compiled
at build time from app/src/main/shaders/clear.frag.
source_ref: "app/src/main/cpp/skyline/gpu/shaders/helper_shaders.cpp:328, app/src/main/cpp/skyline/gpu.cpp:403 (asset filesystem)"
+195
View File
@@ -0,0 +1,195 @@
emulator: "Snes9x EX+"
type: standalone
core_classification: community_fork
source: "https://github.com/Rakashazi/emu-ex-plus-alpha"
upstream: "https://github.com/snes9xgit/snes9x"
profiled_date: "2026-08-12"
source_commit: "1c12fac5ce49badaadff2e2f210dcc30b89f4943"
upstream_commit: "b33f2afb33c61d675aaf0319bd3b8cc8d6924d49"
core_version: "1.5.85"
display_name: "Nintendo - SNES / SFC (Snes9x EX+)"
mode: standalone
cores:
- "snes9x-explus"
- "SNES9X-EXPLUS"
- "Snes9x EX+"
- "Snes9xEXPlus"
systems:
- nintendo-snes
- nintendo-satellaview
- nintendo-sufami-turbo
notes: |
Member of the EX Emulator series by Robert Broglia, published as
com.explusalpha.Snes9xPlus and built around the target s9xp
(Snes9x/metadata/conf.mk:2-7, Snes9x/CMakeLists.txt:4,10). ES-DE reaches it
through the SNES9X-EXPLUS find rule, which only the Android rule set carries,
and offers it under satellaview, sfc, snes, snesna and sufami. Snes9x 1.63 is
vendored under Snes9x/src/snes9x at upstream b33f2af, the revision the sync
commit 96b2f850 names, and 114 of the 152 vendored source files are
byte-identical to it. The app built from Snes9x/1.43 is a separate package,
com.explusalpha.Snes9x, and carries none of what follows.
Content is any .smc, .sfc, .swc, .bs, .st, .fig or .mgd file, or an archive
whose first entry with one of those extensions is used, the app leaving
archives to the framework (Snes9x/src/main/AppMeta.cc:30-33,
EmuFramework/src/EmuSystem.cc:392-425, EmuFramework/src/AppMeta.cc:29). It
is read whole into memory and goes to LoadROMMem, except a Sufami Turbo cart,
recognized by a length of 0x80000 to 0x100000 with "BANDAI SFC-ADX" at 0 and
no "SFC-ADX BACKUP" at 0x10, which goes to LoadMultiCartMem with the base
cartridge placed in front of it (Snes9x/src/main/Main.cc:177-181,221-273,
Snes9x/src/snes9x/memmap.cpp:1575-1608). Dual Sufami Turbo carts are not
loaded: slot B is always passed as null (Snes9x/src/main/Main.cc:250-260).
Two firmware images are read, and both differ from upstream in how they are
found. Upstream opens BS-X.bin then BS-X.bios in its BIOS directory
(bsx.cpp:1204-1236) and STBIOS.bin for a Sufami Turbo load
(memmap.cpp:1663-1686); the app deletes both blocks and reads a URI the user
picks instead, so no filename is compiled in
(Snes9x/src/snes9x/bsx.cpp:1199-1203,
Snes9x/src/snes9x/memmap.cpp:1644-1670, Snes9x/src/main/S9XApi.cc:225-253,
Snes9x/src/main/Main.cc:194-219). Each picker lists directories, names ending
.bin or .bios caselessly, and .7z, .rar and .zip archives, whose first member
with one of those two extensions is taken (Snes9x/src/main/Main.cc:189-192,
Snes9x/src/main/EmuMenuViews.cc:345-387,
EmuFramework/include/emuframework/DataPathSelectView.hh:77-101,
EmuFramework/src/gui/FilePicker.cc:39-48,
imagine/src/fs/ArchiveFS.cc:75-78). An unset path or a failed check throws,
and the loader thread turns that into a failed load with the message on
screen (EmuFramework/src/EmuApp.cc:794-819). Neither image is hashed.
A BS-X cartridge image loaded as content takes the other branch of
S9xInitBSX, which copies it into the BIOS area itself and asks for nothing
(Snes9x/src/snes9x/bsx.cpp:1213-1233). Broadcast data is read per requested
channel as BSXHHHH-D.bin under the Satellaview Files path, which defaults to
the content directory; a miss only leaves the stream unloaded
(Snes9x/src/snes9x/bsx.cpp:736-790, Snes9x/src/main/S9XApi.cc:203-216,
Snes9x/src/main/system.ccm:108).
Every coprocessor is emulated in code with no external firmware: DSP-1 to
DSP-4, ST010, ST011, ST018, Cx4, S-DD1 and SPC7110, each implemented under
Snes9x/src/snes9x in dsp1.cpp through dsp4.cpp, seta010.cpp, seta011.cpp,
seta018.cpp, c4emu.cpp, sdd1emu.cpp and spc7110emu.cpp. The 1.43 branch's
S-DD1 data call and SPC7110 pack directory are compiled out here
(Snes9x/src/main/S9XApi.cc:64,89-131).
Per content the app writes and reads back a .srm, an .rtc for the S-RTC,
.frz states and a .cht cheat list under the cheats path; settings live in
Snes9xP.config (Snes9x/src/main/Main.cc:78-90,153-172,
Snes9x/src/snes9x/memmap.cpp:1791-1812, Snes9x/src/main/Cheats.cc:33-45,
Snes9x/src/main/AppMeta.cc:19). A BS game with no save of its own falls back
to BS-X.srm (Snes9x/src/snes9x/memmap.cpp:1874-1890). A .bps, .ups or .ips
named after the content in the patches path is applied as the image loads,
the app having dropped the search beside the content
(Snes9x/src/snes9x/memmap.cpp:1327,3888-4027). MSU-1 data and tracks are read
beside the content as .msu, or the content name with msu1.rom appended, and
-N.pcm per track (Snes9x/src/snes9x/msu1.cpp:60-70,116-118,157-160). UNZIP_SUPPORT is not defined, so the .msu1 pack and the
patch-inside-a-zip paths are not compiled (Snes9x/CMakeLists.txt:18).
files:
- name: "BS-X.bin"
aliases: ["BS-X.bios"]
system: nintendo-satellaview
description: "Satellaview BS-X cartridge ROM"
required: true
agnostic: true
min_size: 1048576
validation: [existence, size]
config_key: "CFGKEY_BSX_BIOS_PATH"
category: bios
note: >-
Read for every BS game, the branch taken when the header at 0x7FC0 or
0xFFC0 marks the image as one. The read takes 1048576 bytes and compares
the count returned, so a shorter file is rejected and a longer one has its
tail ignored, then the 21 bytes at 0x7FC0 must read "Satellaview BS-X"
padded with spaces.
The name is the user's: the app compiles none in and only the .bin and
.bios endings limit what the picker offers.
source_ref: "Snes9x/src/snes9x/memmap.cpp:2065 (run on every load), Snes9x/src/snes9x/bsx.cpp:1240-1274 (BS branch calls the loader), Snes9x/src/snes9x/bsx.cpp:1199-1203 (loader is the app hook), Snes9x/src/main/S9XApi.cc:218-253 (path, archive, size and header checks), Snes9x/src/main/EmuMenuViews.cc:345-365 (picker), Snes9x/src/main/system.ccm:110 (setting), Snes9x/src/main/options.cc:46,79 (config key)"
- name: "STBIOS.bin"
system: nintendo-sufami-turbo
description: "Sufami Turbo base cartridge ROM"
required: true
agnostic: true
size: 262144
validation: [existence, size]
config_key: "CFGKEY_SUFAMI_BIOS_PATH"
category: bios
note: >-
Read whenever the content is a Sufami Turbo cart, and copied to the front
of the ROM area with the cart behind it. The whole file is buffered, so
the length must be exactly 262144, with "BANDAI SFC-ADX" at 0 and
"SFC-ADX BACKUP" at 0x10. The name is the user's, the picker accepting any
.bin or .bios.
source_ref: "Snes9x/src/main/Main.cc:250-260 (cart routes through the BIOS read), Snes9x/src/main/Main.cc:183-187,194-219 (path, archive, size and header checks), Snes9x/src/snes9x/memmap.cpp:1018-1025,1575-1608 (second check and placement), Snes9x/src/main/EmuMenuViews.cc:367-387 (picker), Snes9x/src/main/system.ccm:109 (setting), Snes9x/src/main/options.cc:45,78 (config key)"
- name: "BSX0120-0.bin"
system: nintendo-satellaview
description: "Satellaview data stream for channel 0120"
required: false
category: game_data
size: 34
validation: [existence]
config_key: "CFGKEY_SATELLAVIEW_PATH"
note: >-
Opened by the name the emulated unit asks for, BSXHHHH-D.bin from the
channel registers at 0x2188 and 0x218E, under the Satellaview Files path,
which defaults to the content directory. The file is measured to size the
queue and read 22 bytes at a time; a miss leaves the stream unloaded.
source_ref: "Snes9x/src/snes9x/bsx.cpp:736-790, Snes9x/src/main/S9XApi.cc:203-216, Snes9x/src/main/system.ccm:108, Snes9x/src/main/EmuMenuViews.cc:325-343"
- name: "BSX0121-0.bin"
system: nintendo-satellaview
description: "Satellaview data stream for channel 0121"
required: false
category: game_data
size: 34
validation: [existence]
config_key: "CFGKEY_SATELLAVIEW_PATH"
source_ref: "Snes9x/src/snes9x/bsx.cpp:736-790, Snes9x/src/main/S9XApi.cc:203-216"
- name: "BSX0122-0.bin"
system: nintendo-satellaview
description: "Satellaview data stream for channel 0122"
required: false
category: game_data
size: 1031
validation: [existence]
config_key: "CFGKEY_SATELLAVIEW_PATH"
source_ref: "Snes9x/src/snes9x/bsx.cpp:736-790, Snes9x/src/main/S9XApi.cc:203-216"
- name: "BSX0123-0.bin"
system: nintendo-satellaview
description: "Satellaview data stream for channel 0123"
required: false
category: game_data
size: 16
validation: [existence]
config_key: "CFGKEY_SATELLAVIEW_PATH"
source_ref: "Snes9x/src/snes9x/bsx.cpp:736-790, Snes9x/src/main/S9XApi.cc:203-216"
- name: "BSX0124-0.bin"
system: nintendo-satellaview
description: "Satellaview data stream for channel 0124"
required: false
category: game_data
size: 97
validation: [existence]
config_key: "CFGKEY_SATELLAVIEW_PATH"
source_ref: "Snes9x/src/snes9x/bsx.cpp:736-790, Snes9x/src/main/S9XApi.cc:203-216"
- name: "Bio Worm.7z"
aliases: ["BioWorm.7z"]
system: nintendo-snes
description: "Bundled homebrew game, listed under Bundled Content"
required: false
bundled: true
category: game_data
validation: [existence]
size: 42479
sha1: "38e44c9868c0b8a5a99ec0b6e901a28f617d25bf"
note: >-
Opened from the application bundle by the name the build gives it, the
Linux build dropping the space, and loaded as content.
source_ref: "Snes9x/src/main/AppMeta.cc:20-21 (names), EmuFramework/src/gui/BundledGamesView.cc:41,47 (open and load)"
+422
View File
@@ -0,0 +1,422 @@
emulator: Speccy
type: standalone
core_classification: other
source: "https://fms.komkon.org/Speccy/"
upstream: closed-source
author: "Marat Fayzullin (Garage Research)"
profiled_date: "2026-08-12"
core_version: "5.9.11"
display_name: "Sinclair - ZX Spectrum and Sam Coupe (Speccy)"
verification: existence
cores:
- speccy
- SPECCY
- com.fms.speccy.deluxe
- com.fms.speccy
systems:
- sinclair-zx-spectrum
- timex-tc2048
- timex-ts2068
- sam-coupe
mode: standalone
notes: |
Sinclair emulator by Marat Fayzullin, covering ZX Spectrum 16kB, 48kB and
128kB, Spectrum +2, +2A and +3, Timex TC2048 and TS2068, the Slovak Didaktik
Gama, the Russian Pentagon and Scorpion clones, and the Sam Coupe. The build
read here is the free Android package com.fms.speccy, versionName 5.9.11
versionCode 5911, taken as the Play app bundle drop, xapk sha256
a93f2fd474234291d2c0dee57885204ffb12a22c94602fdfcdfbf084ed7cb354, base apk
sha256 7163451489ac59b8c63ca49976571ad284cffa11b54d615c1693c909dd6bf768. Its
META-INF/BNDLTOOL.RSA is the author's own key, CN=Marat Fayzullin O=Garage
Research issued 2011, fingerprint
d09469e9b550cbc9005d3bd089f3df5f0ba89cba71cdd3b33736a0382d6f9848, beside a
Play distribution source stamp in the signing block. The paid package
com.fms.speccy.deluxe, last published as 5.9.3 versionCode 5903 in December
2021, is carried by no mirror that answers: the author's site links only to
Play for it, apkcombo bounces its download page back to the app page, apkpure
redirects to its generic downloader, apkvision holds no copy and archive.org
none either. The native libraries keep their symbol tables, so the readings
below cite libmain.so offsets in the x86_64 slice; the arm64-v8a slice carries
the same nineteen ROM names. The free Speccy 5.9 builds for Windows and Ubuntu
were read beside it and open the same names with the same lengths and the same
order. No source has ever been published: every download on the site, from 1.7
for MSDOS through 5.9, is a binary package, while ColEm and fMSX on the same
site ship source archives.
ref: com.fms.speccy.apk META-INF/BNDLTOOL.RSA, https://fms.komkon.org/Speccy/,
Speccy59-Windows-bin.zip, Speccy59-Ubuntu-x86-bin.tgz
One directory holds everything. MainActivity hands the home directory to
jniStart, which copies it into the buffer GetHomeDir returns and passes that
same buffer to SetPrivateDir, and Application stores what GetHomeDir returns as
the directory LoadBIOS changes into before it opens the first ROM and back out
of when it is done. That directory is external storage
joined with the application label up to its first space, so /sdcard/Speccy for
the package read here, falling back to getExternalFilesDirs(null) when it is
not a writable directory; the author's own instructions give the same
placement. Every open goes through mopen, which calls OpenRealFile first: the
name is tried as given, and again as <PrivateDir>/<basename>, keeping the
larger of the two when both open. mopen then layers gzdopen over the
descriptor, so any of these files also opens gzipped, and a content:// name is
routed to the Android storage framework. The desktop builds have no home
directory of their own and open every name where they stand, which -home
changes for the system ROMs alone.
ref: MainActivity.java:2561-2573, EMULib.java:750, 812,
libmain.so jniStart 0x32dd0-0x33530 (0x332af-0x332c1, 0x33312),
GetHomeDir 0x30a90, SetPrivateDir 0x571d0,
Application 0x602f0-0x60324, OpenRealFile 0x57440-0x5766c,
mopen 0x57680-0x57800, LoadBIOS 0x6436d-0x6439a, 0x6466b-0x6467b,
Speccy59-Ubuntu-x86-bin speccy 0x3dae5-0x3db17, Speccy.html
"-home <dirname>", EmuAndroid "System ROMs"
LoadBIOS drives the whole set from one word of hardware flags, calling
TryLoadROM once per name in a fixed order with the length to read and the bit
that asks for it. TryLoadROM does nothing when the bit is clear, and clears
the bit when mopen fails, which is the only check the emulator makes: the
count mread returns is compared against the requested length solely to pick
the word it logs, OK or FAILED, and a short read leaves the bit set. Nothing
else about a file is examined and no hash is compared. A machine ROM that
loads clears every other machine bit and a peripheral ROM that loads clears
every other peripheral bit, so one machine and one disk interface stand at a
time. StartZXS gives up when no machine bit survives, logging FAILED TO LOAD
SYSTEM ROM! and returning zero without starting the emulation, which makes the
ROM of the selected model the one file the emulator cannot run without.
ref: libmain.so LoadBIOS 0x64350-0x646cd, TryLoadROM 0x659b0-0x65aa4
(mopen 0x659d4, mread 0x65a3c, bit cleared 0x65a1c, masks
0x65a7d-0x65a94), StartZXS 0x64040-0x6434c (LoadBIOS 0x6416d, mask
0x64172, message 0x64315), Speccy59-Ubuntu-x86-bin speccy
0x3dac0-0x3ddaa, 0x3d970-0x3da04, 0x3f43c-0x3f469, 0x3f640
Two names are reached only through another. ZXS128TR.ROM is tried in place of
ZXS128.ROM when the 128kB model and the TR-DOS interface are both asked for,
and ZXS128.ROM is loaded after it when it fails. The Multiface bit picks its
image from the machine already loaded, MFPLUS3.ROM behind a +2A or +3,
MF128.ROM behind a 128kB or +2 and MF1.ROM behind a 16kB or 48kB, and the 8192
bytes at offset 8192 of what it read are copied into the page below the machine
ROM.
ref: libmain.so LoadBIOS 0x64564-0x6458b, 0x645d9-0x645f5, 0x645c2-0x64651,
Speccy59-Ubuntu-x86-bin speccy 0x3dc79-0x3dca1, 0x3ddf0-0x3de10,
0x3dcd9-0x3dd64, Speccy.html "Now trying to load ZXS128TR.ROM BIOS file"
Thirteen of the nineteen ROMs ship inside the Android package. MainActivity
reads assets/memfs.mp3 whole and jniStart mounts it through SetMemoryFS as an
in-memory filesystem, which mopen consults only after OpenRealFile has failed,
so a copy in the home directory is served ahead of the packaged one. The
directory is a run of 32 byte entries, a length then a name, closed by an entry
with an empty name whose first word is the key: rotated left by three times the
entry count, XORed sixteen bits at a time into each length and rotated right by
three after each, it yields the thirteen lengths, which run consecutively from
the end of the directory and account for the file exactly. Eleven of the
thirteen are the same bytes the Windows and Ubuntu distributions ship, and
TC2048.ROM and TS2068.ROM appear in no distribution at all.
ref: MainActivity.java:2561-2573, libmain.so jniStart 0x32f72-0x32f98,
InitMemoryFS 0x57180, SetMemoryFS 0x57200-0x57422 (key 0x572a0-0x572c1,
lengths 0x572e0-0x57305), mopen 0x57749-0x577e4
Companion files come from the loaded program's path. LoadFile derives .sta,
.pok, .cht and .pal from it and reads each when it is there, and the startup
palette is a name of its own, <HomeDir>/Speccy.pal on Android and Speccy.pal
beside the binary on the desktop, which -palette redirects.
ref: libmain.so LoadFile 0x65482, 0x65569, 0x65590, 0x655b7,
Application 0x60436-0x60484, StartZXS 0x641c5-0x641d4,
LoadPAL 0x648d0, Speccy59-Ubuntu-x86-bin speccy 0x3f4ac-0x3f4bd,
0x3e450-0x3e494, Speccy.html "-palette <filename>"
files:
- name: ZXS48.ROM
system: sinclair-zx-spectrum
required: true
bundled: true
size: 16384
md5: 4c42a2f075212361c3117015b107ff68
sha1: 5ea7c2b824672e914525d1d5c419d71b84a426a2
crc32: "ddee531f"
description: "ZX Spectrum 48kB BASIC ROM"
note: "Read as 16384 bytes for the 48kB model, which is the model the emulator starts in when nothing else is asked for. Present in the packaged filesystem and in the Windows and Ubuntu distributions."
source_ref: "libmain.so LoadBIOS 0x645a8-0x645bb, Speccy59-Ubuntu-x86-bin speccy 0x3dcbe-0x3dcd1"
- name: ZXS16.ROM
system: sinclair-zx-spectrum
required: true
max_size: 16384
description: "ZX Spectrum 16kB BASIC ROM"
note: "Read for the 16kB model under a name of its own, with no fallback to ZXS48.ROM, so the model refuses to start without it however many other ROMs are present. Neither the package nor the desktop distributions carry a copy."
source_ref: "libmain.so LoadBIOS 0x64590-0x645a3, Speccy59-Ubuntu-x86-bin speccy 0x3dca8-0x3dcbb"
- name: ZXS128.ROM
system: sinclair-zx-spectrum
required: true
bundled: true
size: 32768
md5: 85fede415f4294cc777517d7eada482e
sha1: 16375d42ea109b47edded7a16028de7fdb3013a1
crc32: "2cbe8995"
description: "ZX Spectrum 128kB ROM pair"
note: "Read as 32768 bytes, two pages. Loaded after ZXS128TR.ROM has been tried when the TR-DOS interface is on as well."
source_ref: "libmain.so LoadBIOS 0x64575-0x6458b, Speccy59-Ubuntu-x86-bin speccy 0x3dc85-0x3dca1"
- name: ZXS128TR.ROM
system: sinclair-zx-spectrum
required: false
bundled: true
size: 32768
md5: 44082607f78a3b643f260b0c7e443bbb
sha1: 9b8bc3190086774fe6887e975c81e9976e2711ef
crc32: "ce98811c"
description: "ZX Spectrum 128kB ROM pair carrying TR-DOS"
note: "Tried in place of ZXS128.ROM when the 128kB model and the TR-DOS interface are both asked for, and ZXS128.ROM is loaded in its place when it fails."
source_ref: "libmain.so LoadBIOS 0x645d9-0x645f5, Speccy59-Ubuntu-x86-bin speccy 0x3ddf0-0x3de10"
- name: ZXSPLUS2.ROM
system: sinclair-zx-spectrum
required: true
bundled: true
size: 32768
md5: 238f77692156a5c49d20c0aa2862e8bb
sha1: 8cafb292af58617907b9e6b9093d3588a75849b8
crc32: "e7a517dc"
description: "ZX Spectrum +2 ROM pair"
note: "Read as 32768 bytes for the +2. The +2A bit is cleared ahead of the call whenever the +3 bit is set, so the pair that asks for ZXSPLUS3.ROM cannot leave a second machine standing."
source_ref: "libmain.so LoadBIOS 0x64544-0x6455f, Speccy59-Ubuntu-x86-bin speccy 0x3dc56-0x3dc72"
- name: ZXSPLUS3.ROM
system: sinclair-zx-spectrum
required: true
bundled: true
size: 65536
md5: 7e00ed3562abfd188d0d4da03e80bc0a
sha1: 500c0945760abeefcbd08bc22c0d07b14b336cf0
crc32: "be0d9ec4"
description: "ZX Spectrum +2A and +3 ROM set"
note: "Read as 65536 bytes, four pages covering both the +2A and the +3, which the loader asks for under one bit pair."
source_ref: "libmain.so LoadBIOS 0x6452c-0x6453f, Speccy59-Ubuntu-x86-bin speccy 0x3dc3e-0x3dc51"
- name: TC2048.ROM
system: timex-tc2048
required: true
bundled: true
size: 16384
md5: 9dd7ecf784a6c04265c073c236f5fadb
sha1: febb2d495b6eda7cdcb4074935d6e9d9f328972d
crc32: "f1b5fa67"
description: "Timex Computer 2048 ROM"
note: "Read as 16384 bytes for the TC2048. Carried in the packaged filesystem only: the Windows and Ubuntu distributions ship no copy."
source_ref: "libmain.so LoadBIOS 0x644e4-0x644f7, Speccy59-Ubuntu-x86-bin speccy 0x3dbf6-0x3dc09"
- name: TS2068.ROM
system: timex-ts2068
required: true
bundled: true
size: 24576
md5: 9194283503a105f3f3dfba13e61e993f
sha1: 34cd8113bf75b65a4da6eea355f9d46ad635f7e4
crc32: "48004230"
description: "Timex Sinclair 2068 ROM set"
note: "The loader asks for 49152 bytes while the author's own image is 24576, so the read stops short of what was asked and the machine starts anyway. Carried in the packaged filesystem only."
source_ref: "libmain.so LoadBIOS 0x644cc-0x644df, Speccy59-Ubuntu-x86-bin speccy 0x3dbdd-0x3dbf1"
- name: DIDAKTIK.ROM
system: sinclair-zx-spectrum
required: true
bundled: true
size: 16384
md5: 28287c397defff765b39bd0660da6d01
sha1: 8466a9da0169666210ccff5d43376d70bae0ae9b
crc32: "45c29401"
description: "Didaktik Gama ROM"
note: "Read as 16384 bytes for the Slovak Didaktik Gama clone."
source_ref: "libmain.so LoadBIOS 0x644fc-0x6450f, Speccy59-Ubuntu-x86-bin speccy 0x3dc0e-0x3dc21"
- name: PENTAGON.ROM
system: sinclair-zx-spectrum
required: true
bundled: true
size: 49152
md5: 36e48cd8984702fa9628121f83264ed0
sha1: 582254842091d9f6263652f06c6a86bd54dcf736
crc32: "e7bbb552"
description: "Pentagon 128kB ROM set"
note: "Read as 49152 bytes, three pages. The third is copied into the disk interface window once it has loaded, so the Pentagon carries its own TR-DOS and does not need TRDOS.ROM."
source_ref: "libmain.so LoadBIOS 0x64488-0x644c7, Speccy59-Ubuntu-x86-bin speccy 0x3dbb8-0x3dbd7, 0x3de18-0x3de37"
- name: SCORPION.ROM
system: sinclair-zx-spectrum
required: true
bundled: true
size: 65536
md5: b26cba495108d1227aa5124cd9a1456d
sha1: 66cecdadf992d8adb9c66deee929eb56600dc9bc
crc32: "fef73c28"
description: "Scorpion 256kB ROM set"
note: "Read as 65536 bytes, four pages, the last copied into the disk interface window. The Scorpion bit also drops every peripheral bit before the first ROM is opened, so its own service ROM stands in place of the separate interfaces."
source_ref: "libmain.so LoadBIOS 0x64444-0x64483, 0x643d5-0x643e3, Speccy59-Ubuntu-x86-bin speccy 0x3db94-0x3dbb2, 0x3de40-0x3de5f"
- name: COUPE.ROM
system: sam-coupe
required: true
bundled: true
size: 32768
md5: 9f40c46cce4008e0548db44f39527914
sha1: 58186fd34a8b9c1929913e2b1d7dc4efa507c160
crc32: "39ff160a"
description: "Sam Coupe ROM"
note: "Read as 32768 bytes for the Sam Coupe, which is a machine of its own in the same flag word, so selecting it clears every Spectrum bit and the trapdoor devices are switched off with it."
source_ref: "libmain.so LoadBIOS 0x64514-0x64527, TryLoadROM 0x65a7d-0x65a94, Speccy59-Ubuntu-x86-bin speccy 0x3dc26-0x3dc39, Speccy.html \"Now disabling all trapdoor-based devices in Sam Coupe mode\""
- name: TRDOS.ROM
system: sinclair-zx-spectrum
required: false
bundled: true
size: 16384
md5: 53e2f417c6996df9af170e147df8e369
sha1: 282eb7bc819aad2a12fd954e76f7838a4e1a7929
crc32: "d8882a8c"
description: "Beta Disk TR-DOS interface ROM"
note: "Opened first of all, before any machine ROM, and read as 16384 bytes. A failed open drops the interface and leaves the emulation running without it. Its presence is also what makes the 128kB model reach for ZXS128TR.ROM."
source_ref: "libmain.so LoadBIOS 0x643e6-0x643f7, Speccy59-Ubuntu-x86-bin speccy 0x3db20-0x3db47"
- name: IF1.ROM
system: sinclair-zx-spectrum
required: false
bundled: true
size: 8192
md5: 31b704ae925305e74f50699271fddd9a
sha1: 5cfb6bca4177c45fefd571734576b55e3a127c08
crc32: "bb66dd1e"
description: "Sinclair Interface I ROM"
note: "Read as 8192 bytes when the Interface I is on, and dropped silently when it is missing. Snapshots that page it in need it to restore."
source_ref: "libmain.so LoadBIOS 0x643fc-0x6440f, Speccy59-Ubuntu-x86-bin speccy 0x3db4c-0x3db5f, Speccy.html \"Fixed some .Z80 snapshots not loading when IF1.ROM is missing\""
- name: DISCIPLE.ROM
system: sinclair-zx-spectrum
required: false
max_size: 16384
description: "DISCiPLE disk interface ROM"
note: "Read when the DISCiPLE interface is on, up to 16384 bytes, and dropped silently when it is missing. Neither the package nor the desktop distributions carry a copy."
source_ref: "libmain.so LoadBIOS 0x64414-0x64427, Speccy59-Ubuntu-x86-bin speccy 0x3db64-0x3db77"
- name: PLUSD.ROM
system: sinclair-zx-spectrum
required: false
max_size: 8192
description: "MGT +D disk interface ROM"
note: "Read when the +D interface is on, up to 8192 bytes, and dropped silently when it is missing. Neither the package nor the desktop distributions carry a copy."
source_ref: "libmain.so LoadBIOS 0x6442c-0x6443f, Speccy59-Ubuntu-x86-bin speccy 0x3db7c-0x3db8f"
- name: MF1.ROM
system: sinclair-zx-spectrum
required: false
max_size: 16384
description: "Multiface One ROM"
note: "Read up to 16384 bytes when the Multiface is on behind a 16kB or 48kB machine, and the 8192 bytes at offset 8192 of what it read are copied into the page below the machine ROM. Dropped silently when it is missing."
source_ref: "libmain.so LoadBIOS 0x64605-0x64651, Speccy59-Ubuntu-x86-bin speccy 0x3dea8-0x3deb7, 0x3dcf9-0x3dd0b"
- name: MF128.ROM
system: sinclair-zx-spectrum
required: false
max_size: 16384
description: "Multiface 128 ROM"
note: "Read up to 16384 bytes when the Multiface is on behind a 128kB or +2 machine, and the 8192 bytes at offset 8192 of what it read are copied into the page below the machine ROM. Dropped silently when it is missing."
source_ref: "libmain.so LoadBIOS 0x645f7-0x64651, Speccy59-Ubuntu-x86-bin speccy 0x3dcea-0x3dd0b"
- name: MFPLUS3.ROM
system: sinclair-zx-spectrum
required: false
max_size: 16384
description: "Multiface +3 ROM"
note: "Read up to 16384 bytes when the Multiface is on behind a +2A or +3 machine, and the 8192 bytes at offset 8192 of what it read are copied into the page below the machine ROM. Dropped silently when it is missing. Neither the package nor the desktop distributions carry a copy."
source_ref: "libmain.so LoadBIOS 0x645cb-0x64651, Speccy59-Ubuntu-x86-bin speccy 0x3dee0-0x3dee7, 0x3dcf9-0x3dd0b"
- name: Speccy.pal
required: false
unsourceable: "any palette the user writes, in the text format the parser reads"
category: game_data
description: "startup colour palette"
note: "Built as <HomeDir>/Speccy.pal on Android and taken as the bare name beside the binary on the desktop, loaded once the machine has started and left alone when it is absent. The parser reads the file line by line, skipping blanks and comments, so a palette is text rather than a dump, and -palette points the desktop builds at another name or at one of four built-in palettes."
source_ref: "libmain.so Application 0x60436-0x60484, StartZXS 0x641c5-0x641d4, LoadPAL 0x648d0-0x64c5a, Speccy59-Ubuntu-x86-bin speccy 0x3f4ac-0x3f4bd, 0x3e450-0x3e560"
- name: ROOT.chts
required: false
category: game_data
size: 1652893
md5: b41d9ebf814806a25438a6d937804e54
sha1: 0b53d51635a2ce3d4e12c2077df9aeffeac02517
crc32: "b58e81f1"
description: "cheat database read by the Cheatopedia browser"
note: "The package ships no cheat set. Cheatopedia looks for the file in the package assets, then in the home directory and its subdirectories, and takes it from Speccy-Cheats.zip in the Downloads directory when that is newer, unpacking it into <HomeDir>/Cheats. The author publishes that archive at fms.komkon.org/EmuAndroid/Speccy-Cheats.zip and states it is what re-enables the cheat features Google Play made him disable in March 2019; the copy read here holds this one file."
source_ref: "CheatHelper.java:17-67, Cheatopedia.java:397-427, EmuAndroid \"Cheats support\""
- name: Controls.png
required: false
category: game_data
size: 22587
md5: d10635cb6f101ed733f3d1133bc78f61
sha1: 14c4ab8ccc8ecb81ebf99fec336a3e872c13aabc
crc32: "dc9da322"
description: "virtual joystick skin"
note: "Read as <HomeDir>/Controls.png by the overlay button loader and by the layout editor. The author publishes the template to draw over at fms.komkon.org/EmuAndroid/Controls.png."
source_ref: "MainActivity.java:1100, LayoutEditor.java:415"
- name: Backdrop.png
required: false
category: game_data
unsourceable: "any picture the user places behind the emulated screen"
description: "backdrop drawn around the emulated screen"
note: "Read as <HomeDir>/Backdrop.png. A built-in drawable stands in when the file is absent."
source_ref: "MainActivity.java:1287-1292"
- name: "<game>.back.png"
required: false
category: game_data
unsourceable: "any picture the user places behind one title"
description: "backdrop for one title"
note: "Named from the loaded program's path and preferred over the shared backdrop for that game."
source_ref: "MainActivity.java:1287-1292"
- name: "<game>.pok"
required: false
category: game_data
unsourceable: "POKEs the user writes or collects per title"
description: "POKE list for one title"
note: "Named from the loaded program's path and read by LoadPOK when present."
source_ref: "libmain.so LoadFile 0x65569-0x6558b, LoadPOK 0x692c0"
- name: "<game>.cht"
required: false
category: game_data
unsourceable: "cheat codes the user writes or collects per title"
description: "cheat codes for one title"
note: "Named from the loaded program's path and read by LoadCHT when present. Distinct from the .chts sets of the Cheatopedia browser."
source_ref: "libmain.so LoadFile 0x65590-0x655b2, LoadCHT 0x696a0"
- name: "<game>.pal"
required: false
category: game_data
unsourceable: "any palette the user writes for one title"
description: "colour palette for one title"
note: "Named from the loaded program's path and read by LoadPAL when present, taking effect over the startup palette for that program."
source_ref: "libmain.so LoadFile 0x655b7-0x655d1, LoadPAL 0x648d0"
exclusion_note: >
Left out are the files Speccy writes and reads back itself, which are emulator
state rather than anything a user obtains: <game>.sta holding saved emulation
state, which LoadFile restores ahead of everything else it derives from the
program path, LOG.MID holding the MIDI soundtrack the recorder writes,
<HomeDir>/PrinterOutput.txt holding what the ZX and Timex printers print, and
the replay files of the instant replay recorder. Snapshots, tapes, disk images
and screens are the user's own content: .z80, .sna, .szx, .scs, .tap, .tzx,
.trd, .scl, .fdi, .dsk, .mgt, .sad and .scr all reach LoadFile, and the
emulator writes most of them back. DEFAULT.Z80 is only the name the desktop builds
fall back to when they are started with no file at all. names.dat is left out
because the path is dead in this build: FileInfo opens assets/names.dat and
<HomeDir>/names.dat inside one try block, and no split of the package carries
that asset, so the failed asset read takes the home directory copy down with
it. changelog.html is left out as the release history shown from the menu, read
from the package assets and from nowhere else. The Android audio and graphics
libraries the loader opens by name are provided by the system.
ref: libmain.so LoadFile 0x65380-0x655d1 (0x65482-0x654d4), STAName 0x97ad0,
SndName 0x93970, StartZXS 0x64180-0x6418a, Application 0x603e0-0x6042d,
LoadRPL 0x80040, SaveRPL 0x7fc80, SaveSCR 0x69e70,
FileInfo.java:244-257, EMULib.java:1038, 1067,
Speccy59-Ubuntu-x86-bin speccy 0xbf50,
Speccy.html "[filename] = Name of the file to load [DEFAULT.Z80]"
+116
View File
@@ -0,0 +1,116 @@
emulator: SSF
type: standalone
core_classification: other
source: "https://github.com/shimazzz/SEGASaturnEmulator-SSF"
upstream: closed-source
author: "Shima"
profiled_date: "2026-08-12"
core_version: "PreviewVer R38"
display_name: "Sega - Saturn/ST-V (SSF)"
cores:
- ssf
systems:
- sega-saturn
- sega-stv
mode: standalone
notes: |
Sega Saturn and ST-V emulator by Shima, closed source and distributed as a
binary. Two artifacts are read here and they describe the same emulator: the
Windows build SSF_PreviewVer_R38.zip of 2026-01-01, sha256
7325a9b9d666560ddf632f747fb42ab880f82c45391e51fe0716beb1c535f00b, whose
emulator is the 64-bit SSF.exe and which is cited by virtual address; and the
Android build SSF_AndroidVer.zip of 2022-08-07, package
com.xrea.g2.aaaaaaaa.ssf, whose lib/arm64-v8a/libnative-lib.so keeps its 40738
dynamic symbols and which is cited by symbol. Prose references name the
Japanese documentation shipped in Document/.
Every path below is stored in full in SSF.ini and picked through a file dialog
filtered on "all files (*.*)". SSF fixes no filename and no directory for any
of them and looks for none, so the names used here are the dumps that fill
each slot rather than names the code searches.
Saturn BIOS, [Peripheral] SaturnBIOS. Readme.txt describes the image as the
console address range 00000000-0007FFFF and states that the filename is free.
Neither a length nor a hash is compared against the file. The one routine that
walks the 512 KiB BIOS area is CStateSaveBase::_GetBIOSHash, which folds it
into the checksum pair that tags a save state.
Running without it is a supported mode, [Program4] NoBIOS. SSF carries a boot
ROM of its own, an embedded program with the SYS_* system calls and the
interrupt vectors, and in that mode the backup library is always hooked.
Readme.txt records lower compatibility and advises supplying a BIOS.
ST-V is entered by holding left Shift at launch. [Peripheral] STVBIOS names
the motherboard EPROM, and both the option reference and the No BIOS entry of
Readme.txt state that ST-V does not run without it.
ST-V cartridges are the game and are read from a ZIP: the loader takes the
extension of each member as its IC number, accepts 1 through 13, byte-swaps
every mask ROM in 16-bit units, doubles each byte of the IC13 EPROM across the
16-bit bus, then mirrors each chip over its window. IC7 and IC13 are
exclusive. STV_ROM.html gives the same layout and notes that MAME ROM sets fit
once the extensions are changed.
Cheat scripts live in Cheat/ under the disc product number. Six ship with the
emulator and the memory cheat dialog writes more.
Everything else the binary opens it also writes: SSF.ini, Setting.ini,
Setting/, Backup/, StateSave/, CDIndex/, Snapshot/, Wave/, ExtractSound/,
DebugData/, and the LLVM/ object cache that the bundled CreateObject.exe and
clang.exe compile from the user's own disc for the local CPU.
files:
- name: "sega_101.bin"
aliases:
- mpr-17933.bin
- sega_100.bin
- sega_100a.bin
- sega1003.bin
- hisaturn.bin
- vsaturn.bin
system: sega-saturn
required: false
hle_fallback: true
size: 524288
description: "Saturn BIOS"
note: "Any dump of the 512 KiB console ROM, the compatible machines included. Area code is chosen by [Peripheral] Areacode and AutoAreacode, not by the image, so no region selects this file."
source_ref: "SSF.exe 0x43d770 (SaturnBIOS 0x129b1f8), SSF.exe 0x129a2f8 with the filter at 0x129a310, SSF.exe 0x43ff96 (NoBIOS 0x129b4cc), libnative-lib.so SSF::CStateSaveBase::_GetBIOSHash 0x134b8ec-0x134b924, Document/Readme.txt BIOSファイルについて"
- name: "epr-20091.ic8"
aliases:
- epr-23603.ic8
- epr-19730.ic8
- epr-19854.ic8
- epr-17951a.ic8
- epr-17952a.ic8
- epr-17953a.ic8
- epr-17954a.ic8
- epr-17740.ic8
- epr-17740a.ic8
- epr-17741a.ic8
- epr-17742a.ic8
system: sega-stv
required: true
size: 524288
description: "ST-V BIOS"
note: "Loose 512 KiB EPROM image, read outside the cartridge ZIP. Any of the board revisions is accepted, the code branching on none of them."
source_ref: "SSF.exe 0x43d91f (STVBIOS 0x129b218), SSF.exe 0x129a328, Document/Readme.txt ST-V BIOS option, Document/Readme.txt No BIOS option"
- name: "<cartridge>.bin"
system: sega-saturn
required: false
category: game_data
description: "cartridge image mapped at A-Bus CS0"
note: "[Peripheral] DataCartridge, gated by DataCartridgeEnable and off by default. SSF reads the file at the configured path into the 32 MiB A-Bus CS0 window and identifies it in no way; the dumps that belong there are the two Saturn ROM carts, mpr-18811-mx.ic1 for The King of Fighters '95 and mpr-19367-mx.ic1 for Ultraman. Readme.txt records the option as unverified."
source_ref: "SSF.exe 0x43e26b (DataCartridge 0x1298838), SSF.exe 0x43e178 (DataCartridgeEnable 0x1298820), SSF.exe 0x129a340, SSF.exe 0x916e5e-0x916e84, Document/Readme.txt Data Cartridge option"
- name: "<name>.cht"
path: "Cheat/<product id>/<name>.cht"
system: sega-saturn
required: false
bundled: true
category: game_data
description: "cheat script"
note: "Read when [Program4] EnableCheat is set, from the directory named after the disc product number. The format is a script language: triggers on first read, field, file, sector, CDDA and scanline, memory reads and writes, storage slots, branches and labels. Six ship with the emulator; the memory cheat dialog saves its own with the target address in the name."
source_ref: "SSF.exe 0x4403c0 (EnableCheat 0x1298de0), SSF.exe 0x12998a0, SSF.exe 0x129a658, SSF.exe command table 0x128c570-0x128c808"
+85
View File
@@ -0,0 +1,85 @@
emulator: Starboard
type: standalone
core_classification: other
source: "https://github.com/get-starboard/starboard"
upstream: closed-source
author: "force9"
profiled_date: "2026-08-12"
core_version: "0.23.0"
display_name: "PortMaster library (Starboard)"
verification: existence
cores:
- starboard
- STARBOARD
- org.force9.starboard
systems: []
mode: standalone
notes: |
Catalogue manager and execution environment for the PortMaster library on
Android ARM64 handhelds. PortMaster ports are Linux ARM64 builds, so nothing
is emulated: proot opens a userspace chroot into a Debian bookworm root
filesystem and the games run there as native binaries against glibc, SDL2 and
Mesa. ES-DE reaches it through the ports system, passing a .port file as the
port_file extra to org.force9.starboard/.ui.game.GameActivity.
The build read here is the signed release Starboard-v0.23.0.apk, sha256
a81b69d471ee88ad6c47497e616c5a7c68bf8ebfb32bc7ae9348ed46c3190b3d, matching the
digest GitHub records for the asset. The source is not published, so the
readings below cite a jadx decompilation of classes.dex taken with
--show-bad-code, where org.force9.starboard.* keeps its names and the rest is
r8 output under defpackage.
The APK carries its own execution stack in lib/arm64-v8a: libproot.so,
libproot_loader.so and libtalloc2.so mirrored from Termux through
get-starboard/starboard-prebuilts, libSDL2_starboard.so preloaded ahead of the
SDL2 in the rootfs, libasound_module_pcm_starboard.so as the ALSA output
plugin, libGLESv2_wrap.so with libvirgl_vtest.so and libvirglrenderer_sb.so
for the per-port GPU path, libandroid-shmem.so, and libgame_bridge.so which
starts proot and builds the PortMaster environment. Android installs all of
them with the package.
What the ports find under /opt/system/Tools/PortMaster is written at launch by
libgame_bridge.so: bind_directories.sh, patch_ld_preload.sh,
seed_retroarch_cfg.sh and launcher.sh under /tmp/sb, the gptokeyb shim,
runtimes.json, control.txt and device_info.txt, with etc/resolv.conf and
etc/hosts seeded straight after extraction. The ES-DE sync writes the .port
files it later launches from, each holding a zip_name and a launcher key,
along with a ports entry in custom_systems/es_systems.xml and
gamelists/ports/gamelist.xml.
Games install to Starboard/ports on shared storage, marked by a
.starboard_installed file, and come from the PortMaster catalogue rather than
from this profile. A port that declares a runtime pulls a squashfs image into
opt/system/Tools/PortMaster/libs inside the rootfs on first launch, named by
the port and resolved through the utils index of PortsMaster/PortMaster-New
filtered to arch aarch64. Starboard names no runtime of its own and that index
is republished with the catalogue, so the set belongs to PortMaster.
files:
- name: starboard-rootfs.tar.gz
aliases:
- rootfs.tar.gz
path: "rootfs.tar.gz"
required: true
category: game_data
validation: [sha256]
size: 582086462
sha256: "a40dd11b24802325b37ab6454feb5fda84a6f1de9d769c84a2dd7b6fee8035e1"
unsourceable: "runtime image the app fetches into its own cache and unpacks into internal storage, leaving no path a user or a pack can write"
description: "Debian bookworm ARM64 root filesystem the ports execute in"
note: >-
Fetched from releases/latest/download of get-starboard/starboard-runtime,
written to the cache directory as rootfs.tar.gz, gunzipped into a rootfs
directory under internal storage, then deleted. Nothing launches without
it: the gate reads usr/bin/env and bin/sh in the extracted tree beside
libproot.so in the native library directory. Integrity comes from a
.sha256 sidecar requested next to the asset, whose first whitespace token
must be 64 hex characters; the file is hashed and dropped on a mismatch,
while a missing sidecar logs "No rootfs checksum sidecar available" and the
download is kept on TLS trust alone, which is what happens today since that
sidecar answers 404. The size and hash recorded here identify release
starboard-rootfs-20260604.1, the one that URL served at profiling time, and
the app follows whatever release is latest. Its own version is read back
from etc/starboard-release, which carries release, commit and built keys.
source_ref: "Starboard 0.23.0 ze0.java:75,421-422 (base and asset URL), xe0.java:66-70 (download, verify, extract, delete), ze0.java:236-342 (sha256 sidecar and comparison), ze0.java:130-144 (gunzip into place), ze0.java:416-418 (install directory), ze0.java:426-428 and t20.java:125 (launch gate), ze0.java:439-463 (etc/starboard-release)"
+189
View File
@@ -0,0 +1,189 @@
emulator: SUPER3
type: standalone
core_classification: community_fork
source: "https://github.com/izzy2lost/Super3"
upstream: "https://github.com/trzy/Supermodel"
based_on: "Supermodel 0.3a through the arm branch of DirtBagXon/model3emu-code-sinden at fa1e305"
author: "izzy2lost"
profiled_date: "2026-08-12"
source_commit: "b435c80a88fd496d4a9858be0681260e84342c85"
core_version: "1.2.1"
display_name: "Sega - Model 3 (SUPER3)"
verification: existence
cores:
- super3
- SUPER3
- com.izzy2lost.super3
systems:
- sega-model3
mode: standalone
notes: |
Sega Model 3 emulator for Android, package com.izzy2lost.super3, versionName 1.2.1
versionCode 22, arm64-v8a alone, minSdk 26 and targetSdk 36, GPL-3.0 with the tree in
the open. A Kotlin front end carries the launcher, setup wizard, ini editor and save
state browser over the Supermodel core, built through CMake against SDL2 with an
OpenGL ES presenter of its own. The core states its own lineage: SUPERMODEL_VERSION
reads "0.3a-fa1e305-arm-mm DirtBagXon (Sinden)", and the app names both sources it
draws on, so the emulator is Supermodel 0.3a as carried by the arm branch of
DirtBagXon/model3emu-code-sinden at fa1e305, "Add ManyMouse License" of 2025-07-28.
No upstream commit is pinned because neither this repo nor that fork shares git
history with trzy/Supermodel: both report themselves as independent repositories and
a comparison against trzy/Supermodel has no merge base. ES-DE reaches the app through
its SUPER3 find rule, on Android alone among the seven find rule sets, starting
MainActivity with an intent VIEW whose data is the storage framework URI of the game.
ref: android/app/build.gradle.kts:22-36, Src/Version.h:32, README.md:3-4,
android/app/src/main/java/com/izzy2lost/super3/MainActivity.kt:453-463,
es-de resources/systems/android/es_find_rules.xml:552-557,
es-de resources/systems/android/es_systems.xml:1091
The Android build compiles a subset of the tree, which decides where a load path can
be read. The CMake source list globs Src/ and then drops all of Src/OSD/ and all of
Src/Graphics/ twice over, by regex and again by an explicit removal loop, adding back
only a named list of Src/Graphics/New3D files. So the desktop SDL frontend is absent
from this binary: Src/OSD/SDL/Main.cpp holds the command line and its own config file
handling, Src/OSD/SDL/SDLInputSystem.cpp its own controller database call, and
Src/Graphics/Shader.cpp the loader for external GLSL files, and none of the three is
built here. The paths below are the ones this build actually runs.
ref: android/app/src/main/cpp/CMakeLists.txt:32-91, 135-158
One directory holds everything the emulator reads. MainActivity hands the native side
a user data root of getExternalFilesDir(null)/super3, so
/storage/emulated/0/Android/data/com.izzy2lost.super3/files/super3, and
SetUserDataRoot creates it and changes into it, which is what makes the relative names
below resolve. AssetInstaller copies five trees out of the package assets into that
root before every launch, Assets, Config, GraphicsAnalysis, NVRAM and Saves, never
overwriting a file that is already there, so the emulator always finds its own
configuration whatever the user has done. The native entry point also probes
<root>/super3/Games.xml over external storage, internal storage, /storage/emulated/0
and /sdcard when no path is passed, but the front end always passes one, along with
the ROM path, the game name and the user data root as its four arguments.
ref: android/app/src/main/java/com/izzy2lost/super3/MainActivity.kt:501-503,
1155-1161, 1209-1222,
android/app/src/main/java/com/izzy2lost/super3/AssetInstaller.kt:7-18,
android/app/src/main/cpp/native-lib.cpp:247-260, 1080-1117,
android/app/src/main/java/com/izzy2lost/super3/Super3Activity.kt:99-111
Model 3 boards carry no shared system BIOS and this emulator loads none. Every byte
the machine needs comes out of the per-game MAME format zip: the program ROMs, the
video ROMs, the sound program and samples, and where the board has them the drive
board program, the MPEG program and the MPEG music, all declared as regions of one
game in Games.xml. The set is identified by the basename of the zip, not by a scan,
and the ErrorLog asks for an appropriately named archive when no game answers to that
name; the individual members are then matched by name or by crc32. A child set names a
parent and the loader opens <same directory>/<parent>.zip for the rest of its regions,
which the front end prepares for by walking the parent chain and staging every zip it
names into romcache, refusing to start and naming what is missing when one cannot be
found. This Games.xml declares 63 games with 41 of those lines naming a parent, every
named parent itself a game, and not one non-game or BIOS set among them.
ref: Src/GameLoader.cpp:873-928, 882-890, 913-921, 148-153,
Src/Model3/Model3.cpp:2919-2933,
android/app/src/main/java/com/izzy2lost/super3/MainActivity.kt:1163-1208,
Config/Games.xml
Three files ship inside the package and are read from Config/ at runtime. Games.xml is
the one the emulator cannot do without: InitLoader tests for it and returns failure
when it is absent, which leaves the loading thread in its failed state and no game
running. Supermodel.ini and gamecontrollerdb.txt are both skipped when they are
missing, on built-in defaults in the first case and SDL's built-in controller mappings
in the second. Nothing about any of the three is verified: no length is compared and
no hash is computed, the only tests being that the file is there and that it parses.
ref: android/app/src/main/cpp/native-lib.cpp:531-538, 568-580, 1123-1135,
android/app/src/main/cpp/android_input_system.cpp:291-311,
Src/Util/ConfigBuilders.cpp:60-73, 134-142
Two files that AssetInstaller lands are read by nothing in this build.
Config/Music.xml declares substitute MPEG tracks for DSB1 and DSB2 games, and neither
its own name nor the attributes it is written in appear anywhere in the tree, nor any
handling of mp2 or mp3 files: the DSB reads its music from the mpeg_music region of
the game zip and from nowhere else. Assets/p1crosshair.bmp and Assets/p2crosshair.bmp
are documented by the inherited Manual for a crosshair-style option that does not
exist here, and the tree holds no bitmap reader at all, Src/Util/BMPFile.h being a
writer; the Crosshairs setting is a two bit mask and the presenter draws the crosshair
as geometry. A build that wires either feature up would turn these into files to
collect.
ref: android/app/src/main/assets/Config/Music.xml, Manual.txt:99-102,
Src/Model3/Model3.cpp:2932, Src/Util/BMPFile.h:391,
android/app/src/main/cpp/native-lib.cpp:763-772, 909-976,
android/app/src/main/cpp/gles_presenter.cpp:364-369
The rest of the tree is written, not read. NVRAM/<game>.nv is created on exit and read
back on the next launch of the same game, Saves/ holds the ten save state slots and
their screenshots, romcache/ holds the staged copies of the user's own archives, and
Flyers/ is filled on request from the GitHub contents API of izzy2lost/Model3flyers
for the artwork in the launcher list. An optional sync copies NVRAM, Saves, Config and
Flyers between the internal root and a folder the user picks in the system picker.
ref: android/app/src/main/cpp/native-lib.cpp:262-313, 793-797,
android/app/src/main/java/com/izzy2lost/super3/FlyerRepoSync.kt:16-46,
android/app/src/main/java/com/izzy2lost/super3/UserDataSync.kt:10-25
files:
- name: Games.xml
path: "Config/Games.xml"
required: true
bundled: true
unsourceable: "Installed from the package assets on every launch and never obtained separately"
size: 154928
md5: fc26e2deaa532794d91fe33ca73f8e2c
sha1: b41150f8cff409dde89939b80a980a20e853df0b
crc32: "b2ea6948"
description: "Game and ROM set definitions"
note: >-
The ROM set database, 63 games, giving for each one the regions to fill and the
name and crc32 of every file that fills them, the stepping, the PCI bridge, the
encryption key, the drive board, net board and MPEG board the machine carries, the
patches to apply and the parent set to fall back on. Handed to the GameLoader
constructor, parsed as XML, and a game load is refused outright when the file is
not there. The Kotlin launcher parses the same copy out of the assets for its game
list and its per-game input hints. Byte identical to the copy in the repository
root Config directory.
source_ref: "android/app/src/main/cpp/native-lib.cpp:568-580, 1096-1114, Src/GameLoader.cpp:492-502, 930-933, Src/Util/ConfigBuilders.cpp:60-73, android/app/src/main/java/com/izzy2lost/super3/GameXml.kt:23-24, android/app/src/main/java/com/izzy2lost/super3/MainActivity.kt:1211"
- name: Supermodel.ini
path: "Config/Supermodel.ini"
required: false
bundled: true
unsourceable: "Installed from the package assets on every launch and rewritten in place by the app"
size: 6887
md5: a468e45e005caa89356bd67b70e0d37d
sha1: 6c38cc6fba14863bfbdc730e53d3274fd79a4544
crc32: "2d012d14"
description: "Input and per-game settings"
note: >-
Read after the built-in defaults have been applied, the Global section first and
then the section named after the loaded game, each merged over what is already
set; a file that is absent or unparseable leaves the defaults standing. The hashes
are those of the copy in the package assets, which is not the 13290 byte copy in
the repository root Config directory: the Android build ships its own. They
describe the file as shipped, since AssetInstaller rewrites it on first run,
substituting the Android control defaults, and the in-app editor writes per-game
keys such as LegacyReal3DTiming afterwards.
source_ref: "android/app/src/main/cpp/native-lib.cpp:531-566, 620-621, Src/Util/ConfigBuilders.cpp:134-142, android/app/src/main/java/com/izzy2lost/super3/AssetInstaller.kt:17, 43-159, android/app/src/main/java/com/izzy2lost/super3/Super3Activity.kt:880-884"
- name: gamecontrollerdb.txt
path: "Config/gamecontrollerdb.txt"
required: false
bundled: true
unsourceable: "Installed from the package assets on every launch and never obtained separately"
size: 587398
md5: e8da2d033e90d6fefa884ee78690b4e0
sha1: cb6be8206308470ecaa8b9cc882d82abe0ef3562
crc32: "94468d79"
description: "SDL controller mapping database"
note: >-
Opened once, on the first pad the input system sees, and handed to SDL as mappings
to add. The name is fixed unless the ini key SDLGameControllerDB carries a path of
its own, and a handle that cannot be opened is passed over, leaving SDL on its
built-in mappings. Byte identical to the copy in the repository root Config
directory.
source_ref: "android/app/src/main/cpp/android_input_system.cpp:291-311, 207-213"
exclusion_note: >
No BIOS or firmware file is loaded. Sega Model 3 hardware has no shared system ROM:
each board carries its own program, video, sound and where fitted drive board, MPEG
program and MPEG music ROMs, and every one of them reaches the emulator as a region of
a per-game MAME format zip declared in Games.xml, a child set drawing its remaining
regions from its parent's zip in the same directory. The three files listed above are
the emulator's own configuration, reinstalled from the package assets before every
launch. Config/Music.xml and the two crosshair bitmaps in Assets are shipped by the
package as well and read by no code in this build.
+115
View File
@@ -0,0 +1,115 @@
emulator: Supermodel Dojo
type: standalone
core_classification: enhanced_fork
source: "https://github.com/blueminder/supermodel-dojo"
upstream: "https://github.com/trzy/Supermodel"
author: "blueminder"
profiled_date: "2026-08-12"
source_commit: "ff8cde225298fe5c4ad47fba3c581b2cd19ffc41"
upstream_commit: "77d28eec84a5ededaa23bb31bc74db631cbe5530"
core_version: "dojo-preview6"
display_name: "Sega - Model 3 (Supermodel Dojo)"
verification: existence
cores:
- supermodel-dojo
systems:
- sega-model3
mode: standalone
notes: |
Fork of Supermodel adding delay based netplay, session replay with mid replay
takeover, a training mode, and a launcher binary built from Frontend/. The
emulator side is upstream merged forward: the dojo branch takes trzy/Supermodel
at 77d28ee of 2026-05-28 through merge 627f023, and the commits after it are
launcher fixes. The two repositories are not linked on GitHub, so the pin is
read from the merge itself, whose second parent 77d28ee resolves in both trees
while the first does not.
ref: README.md:4-20, Makefiles/Rules.inc:179-186
Windows and macOS return relative names, Config/, Assets/, NVRAM/, Saves/,
resolved against the working directory, which is where the release archive puts
them and where ES-DE starts the process. Linux uses the working directory when
no home directory resolves, $HOME/.supermodel-dojo/<dir> when that directory
exists, otherwise $HOME/.config/supermodel-dojo/Config and
$HOME/.local/share/supermodel-dojo/<dir> under the XDG variables, and falls back
to the Config/Games.xml and Assets/ sitting next to the binary when the home copy
is absent. Replays/ is a path type there and a working directory folder on Windows.
ref: Src/OSD/Windows/FileSystemPath.cpp:28-56, Src/OSD/OSX/FileSystemPath.cpp:28-54,
Src/OSD/Unix/FileSystemPath.cpp:63-77, 127-138, 141-195, Src/Dojo/Replay.cpp:24-30,
es-de resources/systems/windows/es_systems.xml:171
ROM sets are MAME format per game archives identified by the CRC32 values in
Games.xml, 63 sets at this revision. A parent set holds the ROMs a regional
variant reuses, a relation between versions of one game rather than a shared
BIOS: a split child archive makes the loader open <parent>.zip from the same
directory. Each Model 3 board carries its own program, video, sound and drive
board ROMs, so no system ROM is read outside those archives.
ref: Config/Games.xml, Src/GameLoader.cpp:325-560, Src/GameLoader.cpp:979-1010
The emulator writes and reads back its own Supermodel.ini, generated from the
built in Dojo defaults whenever it is absent, plus NVRAM/<game>.nv,
Saves/<game>.st<slot> and Replays/<game>_<timestamp>.supr with a .st0 sidecar
when the session starts from a save state.
ref: Src/OSD/SDL/Main.cpp:1572-1592, 2425, 713-741, 775-798,
Src/OSD/DojoConfigFile.h:31, Src/Dojo/Replay.cpp:19-50
Two reads take a path the user chooses and have no fixed name: the MP3 tracks
named inside Music.xml, and external GLSL vertex and fragment shaders for the
legacy 3D engine, whose config keys are empty by default so the built in shader
source is compiled instead.
ref: Src/Sound/MPEG/MpegAudio.cpp:71-86, Src/OSD/SDL/Main.cpp:1692-1693,
Src/Graphics/Shader.cpp:93-99
The repository publishes two release trains. The Dojo builds carry the
dojo-preview tags, Preview 6 of 2025-04-27 being the current one, and ship
supermodel.exe, the dojo.exe launcher, Assets/ and Config/. The
v0.3a-<date>-git-<rev> releases come from a workflow that fires only on the
master branch, which tracks upstream: the archive of 2026-06-25 holds Games.xml,
Music.xml and both crosshair names in its binary and none of the Dojo strings.
A build stamps its version from the commit date and short sha, and the tree
falls back to 0.3a-WIP.
ref: .github/workflows/release.yml:4-5, .github/workflows/release.yml:21,
Makefiles/Rules.inc:289-291, Src/Version.h:32
ES-DE reaches it through the SUPERMODEL-DOJO find rule, present in the Windows
set alone among the seven, for the arcade, mame and model3 systems.
ref: es-de resources/systems/windows/es_find_rules.xml:1107-1116,
es-de resources/systems/windows/es_systems.xml:171, 1068, 1220
files:
- name: Games.xml
path: "Config/Games.xml"
required: true
bundled: true
description: "ROM set definitions"
note: "Parsed at startup into the game database. Every ROM region, file name and CRC32 the loader matches against comes from here, so an unreadable file leaves no set to resolve and the launch returns before the emulator is built. The path is a config key, so -game-xml-file moves it."
source_ref: "Src/OSD/SDL/Main.cpp:117, 1684, 2143, 2509-2520, Src/GameLoader.cpp:551-561, 1016-1019, Src/OSD/Windows/FileSystemPath.cpp:28-32"
- name: p1crosshair.bmp
path: "Assets/p1crosshair.bmp"
size: 295992
required: true
bundled: true
unsourceable: "Ships in the release archive next to the binary that loads it"
description: "Player 1 light gun crosshair texture"
note: "Both bitmaps are read on every launch whatever CrosshairStyle holds, since the load runs before the style decides anything, and a null surface aborts startup ahead of the Model 3 object. 32 bit BMP with alpha, sides a multiple of 2."
source_ref: "Src/OSD/SDL/Crosshair.cpp:34-51, Src/OSD/SDL/Main.cpp:2563-2569, Assets/DIR.txt"
- name: p2crosshair.bmp
path: "Assets/p2crosshair.bmp"
size: 295992
required: true
bundled: true
unsourceable: "Ships in the release archive next to the binary that loads it"
description: "Player 2 light gun crosshair texture"
note: "Read in the same call as the player 1 bitmap and equally fatal when it fails to load."
source_ref: "Src/OSD/SDL/Crosshair.cpp:35, 49-51, Src/OSD/SDL/Main.cpp:2563-2569"
- name: Music.xml
path: "Config/Music.xml"
required: false
bundled: true
unsourceable: "Ships in the release archive as a template whose every example sits inside a dummy comment tag"
description: "Custom MPEG music track map"
note: "Consulted only for a game with a DSB1 or DSB2 board, and skipped when the file is absent. Maps an MPEG ROM offset to an MP3 the user supplies."
source_ref: "Src/OSD/SDL/Main.cpp:118, 967, Src/Sound/MPEG/MpegAudio.cpp:88-108"
+45 -3
View File
@@ -26,12 +26,54 @@ notes: |
EmuDeck installs the Flatpak package (com.supermodel3.Supermodel). Config
stored in ~/.supermodel/Config/. No checkBIOS entry in EmuDeck.
files: []
Four data files of its own are read from the install tree, Config/ and Assets/
relative to the working directory on Windows and macOS, under the home
directory on Linux. Supermodel.ini, NVRAM/<game>.nv and Saves/<game>.st<slot>
are written by the emulator itself.
ref: Src/OSD/Windows/FileSystemPath.cpp:28-49
files:
- name: Games.xml
path: "Config/Games.xml"
required: true
bundled: true
description: "ROM set definitions"
note: "Parsed at startup into the game database. Every ROM region, file name and CRC32 the loader matches against comes from here, so an unreadable file leaves no set to resolve and the launch returns before the emulator is built. The path is a config key, so -game-xml-file moves it."
source_ref: "Src/OSD/SDL/Main.cpp:114, 1498, 1939, 2297-2307, Src/GameLoader.cpp:551-561, 1016-1019"
- name: p1crosshair.bmp
path: "Assets/p1crosshair.bmp"
size: 295992
required: true
bundled: true
unsourceable: "Ships in the release archive next to the binary that loads it"
description: "Player 1 light gun crosshair texture"
note: "Both bitmaps are read on every launch whatever CrosshairStyle holds, since the load runs before the style decides anything, and a null surface aborts startup ahead of the Model 3 object. 32 bit BMP with alpha, sides a multiple of 2."
source_ref: "Src/OSD/SDL/Crosshair.cpp:34-51, Src/OSD/SDL/Main.cpp:2350-2356, Assets/DIR.txt"
- name: p2crosshair.bmp
path: "Assets/p2crosshair.bmp"
size: 295992
required: true
bundled: true
unsourceable: "Ships in the release archive next to the binary that loads it"
description: "Player 2 light gun crosshair texture"
note: "Read in the same call as the player 1 bitmap and equally fatal when it fails to load."
source_ref: "Src/OSD/SDL/Crosshair.cpp:35, 49-51, Src/OSD/SDL/Main.cpp:2350-2356"
- name: Music.xml
path: "Config/Music.xml"
required: false
bundled: true
unsourceable: "Ships in the release archive as a template whose every example sits inside a dummy comment tag"
description: "Custom MPEG music track map"
note: "Consulted only for a game with a DSB1 or DSB2 board, and skipped when the file is absent. Maps an MPEG ROM offset to an MP3 the user supplies."
source_ref: "Src/OSD/SDL/Main.cpp:115, 940, Src/Sound/MPEG/MpegAudio.cpp:88-108"
exclusion_note: >
The Sega Model 3 arcade hardware has no shared system BIOS. Each game board
contains its own program ROMs (CROM), video ROMs (VROM), sound program, sound
samples, and optional DSB/drive board ROMs, all contained within per-game
MAME-format ZIP archives. Supermodel loads all required data from these game
ZIPs via CRC32-based identification defined in Games.xml. No standalone BIOS
or firmware files are referenced by the emulator source code.
ZIPs via CRC32-based identification defined in Games.xml. The files listed
above are the emulator's own data, not system ROMs.
+101
View File
@@ -0,0 +1,101 @@
emulator: "Swan.emu"
type: standalone
core_classification: community_fork
source: "https://github.com/Rakashazi/emu-ex-plus-alpha"
upstream: "https://mednafen.github.io/"
profiled_date: "2026-08-12"
source_commit: "1c12fac5ce49badaadff2e2f210dcc30b89f4943"
core_version: "1.5.85"
display_name: "Bandai - WonderSwan / Color (Swan.emu)"
mode: standalone
cores:
- "swan-emu"
- "Swan.emu"
- "SWAN-EMU"
systems:
- bandai-wswan
- bandai-wswanc
notes: |
Member of the EX Emulator series by Robert Broglia, which targets Android and
Linux (README.md:1,3-4,12-13) and keeps iOS and Pandora build shortcuts in the
tree (Swan.emu/ios.mk, Swan.emu/pandora.mk). Published as
com.explusalpha.SwanEmu (Swan.emu/metadata/conf.mk:2,6,7) and reached by ES-DE
through its SWAN-EMU find rule, which only the Android rule set carries.
Mednafen's WonderSwan module, itself descended from Cygne, is vendored under
Swan.emu/src/wswan (Swan.emu/metadata/conf.mk:8,
Swan.emu/src/main/AppMeta.cc:27) on the 1.32 line
(EmuFramework/include/shared/mednafen/mednafen-config.h:167) and driven by the
app's own video, audio, input and save layers. Three files differ from the
Mednafen 1.32.1 release: the pixel format and sound rate hooks move to the app
and the button latch is dropped for a value the input layer writes directly,
the save file calls are removed from loading and closing, and the SRAM and
EEPROM writes signal the app's backup memory
(Swan.emu/src/wswan/main.cpp:91,95, Swan.emu/src/main/Main.cc:96,104,119,
Swan.emu/src/main/input.cc:97,102, Swan.emu/src/wswan/memory.cpp:160-164,
Swan.emu/src/wswan/eeprom.cpp:164-169). The debugger and the disassembler are
left out of the build (Swan.emu/src/CMakeLists.txt:6-22). Content is read from
.ws, .wsc and .bin files (Swan.emu/metadata/conf.mk:5,
Swan.emu/src/main/AppMeta.cc:30); an archive is opened by the framework, which
keeps the first entry passing that same filter
(EmuFramework/src/EmuSystem.cc:394-412).
The content image is the only one the app loads. It is read into a 64 MiB
buffer, refused under 64 KiB or over 64 MiB, rounded up to 64 KiB then to a
power of two with the image sitting at the end of the buffer, and hashed for
the save file names (Swan.emu/src/main/Main.cc:91-97,
EmuFramework/src/shared/mednafen-emuex/MDFNUtils.hh:133-146,
Swan.emu/src/wswan/main.cpp:236-257,294-299). Byte 5 of the footer selects
either an EEPROM of 128, 1024 or 2048 bytes or battery RAM of 8 KiB to 512 KiB
(Swan.emu/src/wswan/main.cpp:317-333). A 512 KiB image carrying ELISA at
0x70000 whose last 16 bytes hash to crc32 0x0d05ed64, minus three blacklisted
images, is taken for WonderWitch firmware and read as content
(Swan.emu/src/wswan/main.cpp:273-291,351-352).
No boot ROM is read. Reset writes a built-in table of 200 power-on values to
the I/O ports, less the four EEPROM data ports
(Swan.emu/src/wswan/start.inc:12,
Swan.emu/src/wswan/main.cpp:66-70) and the memory reset writes at 0x75AC the
eight identifier bytes the boot ROM would have left
(Swan.emu/src/wswan/memory.cpp:801-808). The internal EEPROM is a built-in
0x400 byte image copied at init, then personalized in place with the name,
birth date, sex and blood type of the WonderSwan User Profile menu; the
language flag reaches the hardware the same way
(Swan.emu/src/wswan/eeprom.cpp:31,33,183-214,
Swan.emu/src/wswan/memory.cpp:748-772, Swan.emu/src/wswan/main.cpp:377,
Swan.emu/src/main/EmuMenuViews.cc:34-155,
Swan.emu/src/main/options.cc:117-165).
No firmware path exists by construction: the app answers Mednafen's file name
request for save states, saves and save backups only, and any other kind ends
in unreachable() (Swan.emu/src/main/options.cc:179-189). The module's own save
reader and writer, which would open a .sav and, for WonderWitch, a 524288 byte
.flash image, are unreachable, both call sites of the Mednafen release having
been removed from loading and closing (Swan.emu/src/wswan/memory.cpp:674-740,
Swan.emu/src/wswan/main.cpp:223-226,377-379). The comms setting is answered
false and its program path empty, so the serial link never forks a helper
(Swan.emu/src/main/options.cc:159-160,173-174,
Swan.emu/src/wswan/main.cpp:379, Swan.emu/src/wswan/comm.cpp:40-71). Cheat
loading and IPS patching are compiled in from the shared Mednafen sources and
called from nowhere (EmuFramework/src/shared/CMakeLists.txt:11-12,
EmuFramework/src/shared/mednafen/mempatcher.cpp:251-254,
EmuFramework/src/shared/mednafen/file.cpp:38-53), and the music rip player
routines are stubs (EmuFramework/src/shared/mednafen-emuex/MDFNApi.cc:87-88,
Swan.emu/src/wswan/main.cpp:259-268).
Per content the app writes and reads back one .sav holding the EEPROM followed
by the battery RAM, plus save states and SwanEmu.config
(Swan.emu/src/main/Main.cc:47-54,56-82, Swan.emu/src/main/system.ccm:155,
Swan.emu/src/main/AppMeta.cc:28,
EmuFramework/src/shared/mednafen-emuex/MDFNUtils.hh:76-122,
EmuFramework/src/EmuSystem.cc:168-172). ui.png, gpOverlay.png and the shader
sources are drawn from the application bundle
(EmuFramework/include/emuframework/AssetManager.hh:61-66,
EmuFramework/src/AssetManager.cc:58-70,
EmuFramework/src/VideoImageEffect.cc:163-173), as is the interface font on a
build without fontconfig (imagine/src/font/FreetypeFont.cc:271-289). The app
declares no bundled content, the framework definition defaulting to an empty
span (EmuFramework/src/AppMeta.cc:40,
EmuFramework/include/emuframework/AppMeta.hh:66-68).
files: []
+293
View File
@@ -0,0 +1,293 @@
emulator: "SWF Player"
type: standalone
core_classification: launcher
source: "https://play.google.com/store/apps/details?id=com.issess.flashplayer"
upstream: closed-source
author: "issess.net"
profiled_date: "2026-08-12"
core_version: "1.90 free (build 507)"
display_name: "Adobe Flash (SWF Player)"
mode: standalone
cores:
- "swf-player"
- "SWF Player"
- "SWF-PLAYER"
systems:
- flash
notes: |
Android package com.issess.flashplayer, closed source, published on Google Play and
reached by ES-DE through its SWF-PLAYER find rule. The build read here is 1.90 free
(build 507), versionCode 507, arm64-v8a and armeabi-v7a, sha256
0a56e74d0f8bfdfbd984ce1b8aa2a700203fdd051f3aece3c95fb17f45d4383b, signed v1 and v2 with
the developer certificate O=issess.com, CN=issess, sha256
c3a222b4339f9dde3a770bc1d0ceb551fa96e554679cdbd2056aadd0f1b843c8. Line numbers below are
those of that package: jadx output for the classes, the shipped file itself for
contents.html. The paid package com.issess.flashplayerpro, the other entry of the same
find rule, is built from this class tree, its activity being spelled
com.issess.flashplayer.player.FlashPlayerActivity. No genuine copy of it was obtainable:
apkpure and apkcombo bounce the download of a paid app, apkvision holds none, mi9 serves
zero bytes and archive.org has no item for either package.
Two engines ship in the package, one activity each, both exported and both answering
android.intent.action.VIEW for application/swf, application/x-shockwave-flash and
video/x-flv. FlashPlayerActivity is labelled "SWF Player by Ruffle" and runs the movie
in a WebView; AirPlayerActivity is labelled "SWF Player by AdobeAIR", lives in a :air
process and drives a captive Adobe AIR runtime. ES-DE names the first one and passes the
movie as the content URI of its own provider, so it always gets the Ruffle engine.
ref: AndroidManifest.xml activity com.issess.flashplayer.player.FlashPlayerActivity and
.AirPlayerActivity, string play_ruffle_player, play_air_player, using_ruffle_plugin,
using_air_plugin
The movie itself never stays where the user put it. BaseActivity.E reads the intent Uri
through the content resolver, or opens the path directly for a file:// intent, and writes
the bytes twice: to <cache>/assetLoader/cached.swf for the WebView engine and to
<cache>/app/<uniqueappversionid>/assets/cached.swf for the AIR engine, next to a copy of
the bundled AIR descriptor. The AIR name is fixed because the descriptor declares
cached.swf as its initial window content. A run with no Uri falls back to the last_swf
preference.
ref: BaseActivity.java:607-654, BaseActivity.java:594-605 (uniqueappversionid),
a2/b.java:86-92 (asset copy), a2/b.java:115 (stream copy),
assets/META-INF/AIR/application.xml:28
The Ruffle engine serves everything over a virtual host. FlashPlayerActivity.g0 writes
<cache>/assetLoader/swf.html from the bundled contents.html template, substituting the
movie URL and the wmode, scale, quality, background and density preferences;
FlashPlayerActivity.h0 builds a WebViewAssetLoader on the domain localhost.issess.net
mapping /ruffle/ to the package assets and / to that cache directory; i0 then loads
https://localhost.issess.net/swf.html one second later. The template pulls
/ruffle/ruffle/ruffle.js, which resolves to assets/ruffle/ruffle.js, and declares the
movie as a plain <object type="application/x-shockwave-flash">, which the Ruffle polyfill
takes over. Ruffle is the web build, nightly 2024-08-26, commit
c869505e88f792b1b6691cd8d6f0185bde4c21b9. The player controls are JavaScript calls on
that object and the frame counter comes back through the CallJava bridge.
ref: FlashPlayerActivity.java:262-291, 293-310, 312-346, 154, 349-386,
a2/b.java:327-373, c1/i.java:22-40 (assets handler), c1/i.java:77-95 (cache handler),
assets/contents.html:28,35-49, assets/ruffle/ruffle.js versionName field
Nothing is read from outside the package. The one mention of Adobe's own player is a main
list row that opens market://details?id=com.adobe.flashplayer, a store link that loads no
file, and the "Flash Player Not Found!" branch with its CallJava.notInstalled callback is
the fallback content of the object element, reached only when neither a plugin nor the
polyfill claims it. No plugin binary, BIOS, firmware or key is named anywhere in the
class tree, and ES-DE's own table records no BIOS for this system.
ref: MainListFragment.java:360, a2/b.java:452-468 (market intent),
assets/contents.html:50-60, FlashPlayerActivity.java:179-183,
ES-DE ANDROID.md:928
files:
- name: ruffle.js
path: "assets/ruffle/ruffle.js"
system: flash
required: true
bundled: true
unsourceable: "ships inside the application package"
size: 344533
md5: c0263e609d1aef85891d56d6467a429c
sha1: c58c63e0ae8396018fd71f0fa7ebd4f8eb4f139f
description: "Ruffle web loader and polyfill, nightly 2024-08-26"
note: >-
The only script the generated page includes. It replaces the shockwave-flash object
with a Ruffle player and selects one of the two cores below by WebAssembly feature
detection. Absent, nothing claims the object element and the page renders its fallback
content instead, which reports back through CallJava.notInstalled.
source_ref: "assets/contents.html:28, FlashPlayerActivity.java:305 (/ruffle/ mapped to the package assets)"
- name: "core.ruffle.1c418e86b251861b5eca.js"
path: "assets/ruffle/core.ruffle.1c418e86b251861b5eca.js"
system: flash
required: true
bundled: true
unsourceable: "ships inside the application package"
variant_group: "ruffle-core"
size: 90386
md5: 5b1d64812875a1341ebd2a611e9324a1
sha1: 0eabbed786f3b8e5656d123e9f4573f918ba63d8
description: "Ruffle core bindings, WebAssembly extensions build"
note: >-
Glue for the SIMD core, webpack module 791. Loaded on a device whose WebAssembly
engine carries the extensions, which is what is_wasm_simd_used reports back.
source_ref: "assets/ruffle/ruffle.js webpack module 791, assets/ruffle/core.ruffle.1c418e86b251861b5eca.js is_wasm_simd_used"
- name: "75a2b30a5d3fb1a3431d.wasm"
path: "assets/ruffle/75a2b30a5d3fb1a3431d.wasm"
system: flash
required: true
bundled: true
unsourceable: "ships inside the application package"
variant_group: "ruffle-core"
size: 13107470
md5: 834f85979115fd740943a782887d0ab0
sha1: d27da38e4d37727a44bf04d7690a09135fad7115
description: "Ruffle core, WebAssembly extensions build"
note: >-
The player itself for devices with the extensions. Its target features record simd128,
which the baseline build below does not carry.
source_ref: "assets/ruffle/ruffle.js webpack module 791"
- name: "core.ruffle.9fa2f1e6feaba5f6767a.js"
path: "assets/ruffle/core.ruffle.9fa2f1e6feaba5f6767a.js"
system: flash
required: true
bundled: true
unsourceable: "ships inside the application package"
variant_group: "ruffle-core"
size: 94169
md5: 5aee868a91c066cc15f8b06999af690b
sha1: 45815723a1bdf4229e289906bf4e52dbfd78da56
description: "Ruffle core bindings, baseline build"
note: >-
Glue for the core without WebAssembly extensions, webpack module 797. Loaded when the
device does not report them.
source_ref: "assets/ruffle/ruffle.js webpack module 797, assets/ruffle/core.ruffle.9fa2f1e6feaba5f6767a.js is_wasm_simd_used"
- name: "9541e862775deeb49470.wasm"
path: "assets/ruffle/9541e862775deeb49470.wasm"
system: flash
required: true
bundled: true
unsourceable: "ships inside the application package"
variant_group: "ruffle-core"
size: 13323601
md5: fe843bd0152c714f0449493b0193108f
sha1: fea8e60e86cba7a63258626b13e6adb69ed110f9
description: "Ruffle core, baseline build"
note: >-
The player itself for devices without the WebAssembly extensions.
source_ref: "assets/ruffle/ruffle.js webpack module 797"
- name: contents.html
path: "assets/contents.html"
system: flash
required: true
bundled: true
unsourceable: "ships inside the application package"
size: 2421
md5: 39c997db73db15a6807b35f148fcc85a
sha1: 0aaf20633888d2d0a2da38e82773cb5d44e840eb
description: "Template of the page the WebView loads"
note: >-
Read from the assets on every launch and rewritten into
<cache>/assetLoader/swf.html with the movie URL and the display preferences
substituted. It carries the ruffle.js include and the object element. Unreadable, the
generator returns null and the WebView is pointed at a page with no movie in it.
source_ref: "a2/b.java:327-333, FlashPlayerActivity.java:276-291"
- name: application.xml
path: "assets/META-INF/AIR/application.xml"
system: flash
required: true
bundled: true
unsourceable: "ships inside the application package"
size: 1377
md5: de36d0dc1b74a39be2313749138d4d00
sha1: bc283d9ad8ad3bb99b632ca5b194a5bf27df1c22
description: "Adobe AIR application descriptor, namespace 3.8"
note: >-
Copied out of the assets into <cache>/app/<uniqueappversionid>/assets/META-INF/AIR/
before the AIR engine starts, and read from there by the runtime. It declares
cached.swf as the initial window content, which is the name the movie is copied under,
plus fullscreen, gpu rendering and auto orientation.
source_ref: "BaseActivity.java:616-630, assets/META-INF/AIR/application.xml:19,27-35"
- name: libCore.so
path: "lib/arm64-v8a/libCore.so"
system: flash
required: true
bundled: true
unsourceable: "ships inside the application package"
size: 20951456
md5: 7fa4474455635584fa683167ee7e948f
sha1: d6d91ca32cbceda054851e9aa78c2e9286bd8812
description: "Adobe AIR 51.1.1.3 captive runtime"
note: >-
The AIR player, loaded by path first and then by name from the package. The runtime is
captive: the wrapper classes live in the application's own dex and the library beside
them, so no separate AIR package is consulted. The armeabi-v7a build of the same
version is 14808220 bytes. Version read back from the library as "AND 51,1,1,3".
source_ref: "AndroidActivityWrapper.java:455-481, AirPlayerBaseActivity.java:59-70"
- name: libc++_shared.so
path: "lib/arm64-v8a/libc++_shared.so"
system: flash
required: true
bundled: true
unsourceable: "ships inside the application package"
size: 1058904
md5: 77f7b0c9bba5c0b4c4339bc655d5613a
sha1: 8db47ede06074dec3fbc05b69eb75f8c1c5e71a8
description: "NDK C++ runtime for the AIR runtime"
note: >-
Named by the wrapper ahead of the runtime itself, by path and then by name, and listed
as a DT_NEEDED of libCore.so. The armeabi-v7a build is 657000 bytes.
source_ref: "AndroidActivityWrapper.java:459,472-478"
- name: libswfplayer.so
path: "lib/arm64-v8a/libswfplayer.so"
system: flash
required: true
bundled: true
unsourceable: "ships inside the application package"
size: 3896
md5: 1301640830c754d20384243c97bd7854
sha1: 6118faa7947eb7abf4326f08f5ba94ab61e42808
description: "JNI library of the application"
note: >-
Loaded from the static initializer of the AIR activity's base class, so its absence
stops that activity from being created. It exports one symbol,
Java_com_issess_flashplayer_stringFromJNI, which nothing calls. The armeabi-v7a build
is 2688 bytes.
source_ref: "AirPlayerBaseActivity.java:31-33"
- name: sample1.swf
path: "assets/sample1.swf"
system: flash
required: false
bundled: true
unsourceable: "ships inside the application package"
size: 5889
md5: 3d801b57e0b9e1a84d9cf28ef7505b3c
sha1: 5194da518b3bbc77204e481c2cfed0381cf5df41
description: "Sample movie"
note: >-
Unpacked into <cache>/assetLoader on the sample list screen, then opened through a
chooser like any other movie so either engine can take it.
source_ref: "SampleListFragment.java:65-81, 109-117"
- name: sample2.swf
path: "assets/sample2.swf"
system: flash
required: false
bundled: true
unsourceable: "ships inside the application package"
size: 54675
md5: c583c7db1c5456c0d9307d5f510a63f0
sha1: bef0ab96169418441f43b9dae2ec92a990b89ade
description: "Sample movie"
note: >-
Unpacked and opened on the same path as sample1.swf.
source_ref: "SampleListFragment.java:65-81, 109-117"
- name: sample3.swf
path: "assets/sample3.swf"
system: flash
required: false
bundled: true
unsourceable: "ships inside the application package"
size: 23563
md5: 505834e937b0bd061695ff34f40301cb
sha1: f5992aebd3ba298f6564681592be8b4626e89158
description: "Sample movie"
note: >-
Unpacked and opened on the same path as sample1.swf.
source_ref: "SampleListFragment.java:65-81, 109-117"
exclusion_note: >
Four files the package carries are left out because no code path opens them. The assets
cached.swf, Hello2.swf and empty.html are named in no class; the cached.swf the AIR
runtime reads is the copy of the user's movie written into the cache, not the one in the
assets. libysshared.so, which exports only ysEncrypt and ysDecrypt, is loaded by nothing:
the three loadLibrary calls in the package name swfplayer, c++_shared and Core, no
library declares it as a DT_NEEDED, and its soname appears nowhere in the class tree. The
market link to com.adobe.flashplayer is not a dependency either, being an intent to the
store page rather than a load of Adobe's plugin.
+226
View File
@@ -0,0 +1,226 @@
emulator: Virtual Virtual Boy
type: standalone
core_classification: other
source: "https://github.com/SupernaviX/vvb"
upstream: "https://github.com/SupernaviX/vvb"
author: "Simon Gellis"
profiled_date: "2026-08-12"
source_commit: "0bf230bced628d78ff2c149baaf16f6fb8388cec"
upstream_commit: "0bf230bced628d78ff2c149baaf16f6fb8388cec"
core_version: "1.18.2"
display_name: "Nintendo - Virtual Boy (Virtual Virtual Boy)"
mode: standalone
cores:
- virtual-virtual-boy
- VIRTUAL-VIRTUAL-BOY
- vvb
- com.simongellis.vvb
- com.simongellis.vvb.leia
systems:
- nintendo-virtualboy
notes: |
Virtual Boy emulator for Android, published as com.simongellis.vvb
(app/build.gradle:62,65-66) and reached by ES-DE through its
VIRTUAL-VIRTUAL-BOY find rule, which hands the game over as an ACTION_VIEW
intent on a content URI (MainActivity.kt:126-131, MainActivity.kt:40-45). The
hardware sits in a Rust library packaged as libvvb.so and loaded when the
application starts (VvbApplication.kt:69, Cargo.toml [lib]); the Kotlin side
owns the menus, the input mapping and every file access. Display goes through
mono, anaglyph, stereo, Google Cardboard and Leia CNSDK renderers, each
carrying its GLSL as string constants in the Rust sources
(src/video/renderers/mono.rs:10-26, src/video/renderers/stereo.rs:13-29).
The console has no boot ROM and the emulator loads none. The memory map
declares Vram, Audio, Hardware, Dram, Sram and Rom, and load_game_pak takes
the cartridge image and its SRAM, leaving the Rom region unpopulated until a
game arrives (src/emulator/memory.rs:8-14, src/emulator/memory.rs:115,
src/emulator/memory.rs:134-149).
Games are read from .vb, .vboy and .bin, or from the first member of a zip
answering the same test (GamePakLoader.kt:20-27, GamePakLoader.kt:97-98). The
image has to be a power of two and at most 0x01000000 bytes, either test
aborting the load (GamePakLoader.kt:39-45, GamePakLoader.kt:57), and the core
applies the same two limits again when the image reaches it
(src/emulator/memory.rs:136-141). The MD5 of the image names the directory
that holds the save data, where the app writes .srm and
save_states/<slot>.sav as it runs (GamePakLoader.kt:30-32,
GamePak.kt:8-9,30, src/emulator/state.rs:30-38). Cardboard lens parameters
come from scanning the viewer QR code and are kept by the SDK, the app asking
for them and starting a scan when none are saved
(src/video/renderers/cardboard.rs:29-34).
One tree ships two flavours: playStore, and leia, which appends .leia to the
application id and renders through the CNSDK (app/build.gradle:92-100). Both
carry the same nine homebrew titles, stored uncompressed so they can be opened
by descriptor (app/build.gradle:117).
files:
# -- Bundled homebrew, assets/games, listed by res/raw/bundledgames.json --
# Each title is served over content://com.simongellis.vvb.assets and then read
# through the same path as a user game, so the power of two and 0x01000000
# tests apply to it. The id an entry declares is the MD5 of the image.
# Common refs: BundledGameRepository.kt:9-13, AssetsProvider.kt:18-19,
# GamePakLoader.kt:35-49.
- name: "BLOX.vb"
path: "games/BLOX.vb"
system: nintendo-virtualboy
required: false
bundled: true
category: game_data
md5: f82d4c9fdd81518537d88f70c6602bb5
sha1: f2105349dff09bdc00e4548460991dde9ac7c2af
max_size: 16777216
validation: [size]
description: "Bundled homebrew game by KR155E"
source_ref: "app/src/main/res/raw/bundledgames.json:2-7, app/src/main/java/com/simongellis/vvb/data/BundledGameRepository.kt:9-13, app/src/main/java/com/simongellis/vvb/AssetsProvider.kt:18-19, app/src/main/java/com/simongellis/vvb/game/GamePakLoader.kt:35-49"
- name: "BLOX 2.vb"
path: "games/BLOX 2.vb"
system: nintendo-virtualboy
required: false
bundled: true
category: game_data
md5: cc91d6389df2c9777919e8e8ab2c0e66
sha1: 66b2a25ef8e1af74bed4bbba4785951a9d6edce0
max_size: 16777216
validation: [size]
description: "Bundled homebrew game by KR155E"
source_ref: "app/src/main/res/raw/bundledgames.json:8-13, app/src/main/java/com/simongellis/vvb/data/BundledGameRepository.kt:9-13, app/src/main/java/com/simongellis/vvb/AssetsProvider.kt:18-19, app/src/main/java/com/simongellis/vvb/game/GamePakLoader.kt:35-49"
- name: "Elevated Speed.vb"
path: "games/Elevated Speed.vb"
system: nintendo-virtualboy
required: false
bundled: true
category: game_data
md5: 8f7bcfdd0f412d9060b06a97a89fe202
sha1: 8b08f08f37127621483aa4e204a3e3b2312af196
max_size: 16777216
validation: [size]
description: "Bundled homebrew game by PizzaRollsRoyce"
source_ref: "app/src/main/res/raw/bundledgames.json:14-19, app/src/main/java/com/simongellis/vvb/data/BundledGameRepository.kt:9-13, app/src/main/java/com/simongellis/vvb/AssetsProvider.kt:18-19, app/src/main/java/com/simongellis/vvb/game/GamePakLoader.kt:35-49"
- name: "Fishbone.vb"
path: "games/Fishbone.vb"
system: nintendo-virtualboy
required: false
bundled: true
category: game_data
md5: 61e38e4e0c43aa8d6274a89ebedd3063
sha1: b1e5d5ab7e49f91050d3593bbcf48ff609c1c979
max_size: 16777216
validation: [size]
description: "Bundled homebrew game by thunderstruck"
source_ref: "app/src/main/res/raw/bundledgames.json:20-25, app/src/main/java/com/simongellis/vvb/data/BundledGameRepository.kt:9-13, app/src/main/java/com/simongellis/vvb/AssetsProvider.kt:18-19, app/src/main/java/com/simongellis/vvb/game/GamePakLoader.kt:35-49"
- name: "Formula V Public Demo.vb"
path: "games/Formula V Public Demo.vb"
system: nintendo-virtualboy
required: false
bundled: true
category: game_data
md5: 34e9a2ffd60f7ea565caada82d57f29f
sha1: 533672b887ec16aa50a5508488d1ab125dd5e749
max_size: 16777216
validation: [size]
description: "Bundled homebrew game by KR155E"
source_ref: "app/src/main/res/raw/bundledgames.json:26-31, app/src/main/java/com/simongellis/vvb/data/BundledGameRepository.kt:9-13, app/src/main/java/com/simongellis/vvb/AssetsProvider.kt:18-19, app/src/main/java/com/simongellis/vvb/game/GamePakLoader.kt:35-49"
- name: "Red Square.vb"
path: "games/Red Square.vb"
system: nintendo-virtualboy
required: false
bundled: true
category: game_data
md5: 9c372321204b9fa65f9324f98aae53ff
sha1: a12529a0d7cf7f0711b913b8ae72fea193cebc17
max_size: 16777216
validation: [size]
description: "Bundled homebrew game by Kresna and Nyrator"
source_ref: "app/src/main/res/raw/bundledgames.json:32-37, app/src/main/java/com/simongellis/vvb/data/BundledGameRepository.kt:9-13, app/src/main/java/com/simongellis/vvb/AssetsProvider.kt:18-19, app/src/main/java/com/simongellis/vvb/game/GamePakLoader.kt:35-49"
- name: "The Red Castle.vb"
path: "games/The Red Castle.vb"
system: nintendo-virtualboy
required: false
bundled: true
category: game_data
md5: cdb404ff3e1df7b3c13214ac5409d512
sha1: 34e90abaa3ffc706882fd8a0d1a8101abc185734
max_size: 16777216
validation: [size]
description: "Bundled homebrew game by Timothy Beck"
source_ref: "app/src/main/res/raw/bundledgames.json:38-43, app/src/main/java/com/simongellis/vvb/data/BundledGameRepository.kt:9-13, app/src/main/java/com/simongellis/vvb/AssetsProvider.kt:18-19, app/src/main/java/com/simongellis/vvb/game/GamePakLoader.kt:35-49"
- name: "VUE Snake.vb"
path: "games/VUE Snake.vb"
system: nintendo-virtualboy
required: false
bundled: true
category: game_data
md5: ccfa400a0ff3d717dad36a3f736fd34d
sha1: 77ebaf5dbe667d8347d098b6749b6f3be09f5814
max_size: 16777216
validation: [size]
description: "Bundled homebrew game by KR155E"
source_ref: "app/src/main/res/raw/bundledgames.json:44-49, app/src/main/java/com/simongellis/vvb/data/BundledGameRepository.kt:9-13, app/src/main/java/com/simongellis/vvb/AssetsProvider.kt:18-19, app/src/main/java/com/simongellis/vvb/game/GamePakLoader.kt:35-49"
- name: "VUEngine Platformer Demo.vb"
path: "games/VUEngine Platformer Demo.vb"
system: nintendo-virtualboy
required: false
bundled: true
category: game_data
md5: c96d91fb97572a0af7d53f63b292e0f2
sha1: b1b9893629bbec74e8b58d7b5983e7d35e202fe0
max_size: 16777216
validation: [size]
description: "Bundled homebrew game by KR155E"
source_ref: "app/src/main/res/raw/bundledgames.json:50-55, app/src/main/java/com/simongellis/vvb/data/BundledGameRepository.kt:9-13, app/src/main/java/com/simongellis/vvb/AssetsProvider.kt:18-19, app/src/main/java/com/simongellis/vvb/game/GamePakLoader.kt:35-49"
- name: bundledgames.json
path: "res/raw/bundledgames.json"
system: nintendo-virtualboy
required: false
bundled: true
category: game_data
md5: 04ecc37b70b23fdcc3f5207040f4d178
sha1: 2ae5b46e78afb1bb95d11fa103d6176321573b91
size: 1677
description: "Index of the bundled homebrew titles"
note: >-
Read whole as a raw resource when the repository is built, and decoded
into the list the load menu offers. Each record names the title, the
content URI serving it, the authors and the MD5 of the image. The leia
flavour replaces the file with one pointing at its own authority.
source_ref: "app/src/main/java/com/simongellis/vvb/data/BundledGameRepository.kt:9-13, app/src/main/java/com/simongellis/vvb/data/BundledGame.kt:7-13, app/src/leia/res/raw/bundledgames.json:5"
# -- Preview frames, decoded unscaled and pushed into the eye buffers --
# Both are 384x224 in four shades, the shape the display expects, and they
# stand in for a running game while the video settings are being adjusted.
- name: vbtitlescreen_left.png
path: "res/drawable-nodpi/vbtitlescreen_left.png"
system: nintendo-virtualboy
required: false
bundled: true
category: game_data
md5: 793565cb6af20eb02c78322899e54172
sha1: 480e9872ab20d8a137004e45486985608882983f
size: 619
description: "Left eye of the settings preview image"
source_ref: "app/src/main/java/com/simongellis/vvb/game/GameViewModel.kt:41-51, app/src/main/java/com/simongellis/vvb/game/PreviewActivity.kt:32,56"
- name: vbtitlescreen_right.png
path: "res/drawable-nodpi/vbtitlescreen_right.png"
system: nintendo-virtualboy
required: false
bundled: true
category: game_data
md5: 6df7af05e6b0cb19a37615c2b29116d9
sha1: fc6c5857a0c298d9d6a73449044d1ef3c57fe050
size: 620
description: "Right eye of the settings preview image"
source_ref: "app/src/main/java/com/simongellis/vvb/game/GameViewModel.kt:41-51, app/src/main/java/com/simongellis/vvb/game/PreviewActivity.kt:32,56"
+263
View File
@@ -0,0 +1,263 @@
emulator: X1 BOX
type: standalone
core_classification: community_fork
source: "https://github.com/izzy2lost/xemu"
upstream: "https://github.com/xemu-project/xemu"
author: "izzy2lost"
profiled_date: "2026-08-12"
source_commit: "3ed53f6843ac41147287468d996dfa939b40ad00"
upstream_commit: "26fcbe54f17e496bdf530dad9f237e74e2f943fc"
core_version: "1.2.6"
display_name: "Microsoft - Xbox (X1 BOX)"
cores:
- "x1-box"
- "x1box"
systems:
- microsoft-xbox
mode: standalone
notes: |
Original Xbox emulator for Android, package com.izzy2lost.x1box, arm64-v8a.
A Kotlin front end carries the launcher, setup wizard, game library, settings
and per-title overrides, and drives a whole xemu tree built through CMake
against SDL2 and QEMU 10.2.0. The imgui interface, the monitor and the
snapshot entry points are stubbed, so that front end is the only interface.
.LauncherActivity answers VIEW with a content or file URI, and that URI
becomes the disc slot before emulation opens.
ref: QEMU_VERSION,
android/app/build.gradle.kts:49, 55, 64-65, 68,
android/app/src/main/AndroidManifest.xml:13-30,
android/app/src/main/cpp/CMakeLists.txt:858, 867-868,
android/app/src/main/java/com/izzy2lost/x1box/LauncherActivity.kt:37,
92-121
The wizard walks four steps and each Next stays disabled until its own step
resolves: the MCPX boot ROM, the flash ROM, the disk image and a games
folder. The two ROM pickers keep .bin, .rom and .img, the disk picker .qcow2
and .img. A pick is fingerprinted before anything is written, and only a file
that passes is copied into x1box under the external files directory as
mcpx.bin, flash.bin or hdd.img; a file chosen as a path in place is kept as
that path instead. Those names, the eeprom the wizard never asks for and the
disc are written to x1box/xemu.toml under sys.files. The disc is handed to
QEMU as a file descriptor through -add-fd and only copied to x1box/dvd.iso
when that fails.
ref: android/app/src/main/java/com/izzy2lost/x1box/SetupWizardActivity.kt:63-139,
243-278, 411-459,
android/app/src/main/cpp/xemu_android.cpp:717-721, 757-870, 1315-1325
The three images are what the app gates on. The launcher sends the user back
through the wizard whenever the MCPX, the flash, the disk or the games folder
stops resolving, and an intent from a frontend reaches the emulator only once
the three images resolve. The core underneath is looser: an empty MCPX path
simply leaves the machine property off, an empty disk path attaches no drive
at index 0, and only the flash clears autostart on its own.
ref: android/app/src/main/java/com/izzy2lost/x1box/LauncherActivity.kt:117-135,
system/vl.c:3000-3022, 3057-3072, 3078-3092
Settings imports a dashboard tree from a ZIP or a folder into the FATX
partitions of the configured disk image, C at 0x8CA80000 and E at 0xABE80000,
keeping what it overwrites in a dated backup folder. The tree is searched for
a boot XBE beforehand and the best candidate is copied to C/xboxdash.xbe when
that name is missing, xboxdash.xbe, default.xbe, evoxdash.xbe, avalaunch.xbe,
unleashx.xbe, xbmc.xbe and nexgen.xbe scoring in that order, with a name
carrying dash and a path under dashboard scoring above one under apps or
games. The status line probes C for xboxdash.xbe, msdash.xbe, xbox.xtf and
the directories xodash, audio, fonts and xboxdashdata.*, and calls the
install complete when the boot XBE sits beside at least one of the others.
ref: android/app/src/main/cpp/xemu_fatx_import.c:51-54, 1786-1801, 1842-1847,
1864-1911,
android/app/src/main/java/com/izzy2lost/x1box/XboxInsigniaHelper.kt:10-53,
android/app/src/main/java/com/izzy2lost/x1box/SettingsActivity.kt:2370-2445
Preparing Insignia turns the NAT backend on and writes the DNS 46.101.64.175
into the config sector of the disk image and into the EEPROM at 0xAC.
Registration boots a Setup Assistant image the user picks, which goes in the
disc slot like any other game. The disk tools format an image that already
exists and never create one: a retail layout needs at least 0x1DD156000
bytes and the extended F and G layouts need room past that boundary. The
EEPROM editor rewrites language, video standard, resolution flags, aspect
ratio and refresh rate in place and recomputes both checksums. The five
managed files travel together through an x1box-files-*.zip archive that
settings both writes and reads back.
ref: android/app/src/main/java/com/izzy2lost/x1box/XboxInsigniaHelper.kt:7-8,
62-77,
android/app/src/main/java/com/izzy2lost/x1box/XboxEepromEditor.kt:17,
159-213,
android/app/src/main/java/com/izzy2lost/x1box/XboxHddFormatter.kt:7-16,
46-50,
android/app/src/main/java/com/izzy2lost/x1box/SettingsActivity.kt:48-56,
1030-1086, 1432-1445
files:
- name: mcpx_1.0.bin
required: true
path: "x1box/mcpx.bin"
config_key: "sys.files.bootrom_path"
size: 512
md5: "d49c52a4102f6df7bcf8d0617ac475ed"
validation: [size, md5]
description: "MCPX southbridge boot ROM"
note: >-
The only file the app verifies by content. A pick is accepted just when
its MD5 equals the value hardcoded in the wizard, which is the v1.0 boot
ROM; anything else is refused with the expected hash quoted, and the
512-byte dump whose MD5 is 196a5f59a13382c185636e691d6c323d is named
separately as a known bad dump to re-dump. The check runs again over the
stored copy every time the wizard opens, so a file that stops matching
is dropped. The loader then checks the size a second time and ends the
process when it is not 512 bytes. The bytes are read over the last 512
of the flash image and the region stays writable so early retail kernels
keep their cache quirk.
source_ref: "android/app/src/main/java/com/izzy2lost/x1box/SetupWizardActivity.kt:23-25, 67-91, 411-459, 461-500, android/app/src/main/res/values/strings.xml:19-21, system/vl.c:2998-3022, hw/xbox/xbox.c:143-172"
- name: Complex_4627.bin
required: true
path: "x1box/flash.bin"
config_key: "sys.files.flashrom_path"
size_options: [262144, 524288, 1048576]
size_note: "Any non-zero multiple of 65536; 256 KB is assumed when the image cannot be read."
validation: [size]
description: "Xbox flash ROM"
note: >-
Passed as -bios, and the one image whose absence stops the run on its
own: a path that cannot be opened queues an error and clears autostart.
The picker only refuses what looks like the boot ROM, a 512-byte file or
either MCPX hash, and asks for a BIOS instead; there is no positive hash
to match. The image is mapped at 0xFF000000 and mirrored to the top of
the address space; a size that is zero or not a multiple of 64 KB, or a
short read, falls back to 256 KB filled with 0xFF. A retail image cannot
launch unsigned code, so a debug or modified image is what boots a title.
source_ref: "system/vl.c:3057-3072, hw/xbox/xbox.c:64-102, android/app/src/main/java/com/izzy2lost/x1box/SetupWizardActivity.kt:64, 93-116, 487-495"
- name: xbox_hdd.qcow2
required: true
path: "x1box/hdd.img"
config_key: "sys.files.hdd_path"
description: "Xbox hard disk image"
note: >-
Taken in qcow2 or raw form and attached as index 0 with locked=on and
cache=writethrough. An empty setting attaches no drive at all and an
unopenable one only queues a message, but the launcher refuses to leave
the wizard until the file resolves. The formatter builds FATX partitions
inside an image that already exists and needs at least 0x1DD156000 bytes
for the retail layout; it never creates the image. Partitions C and E of
this image are what the dashboard import writes into.
source_ref: "system/vl.c:3078-3092, android/app/src/main/java/com/izzy2lost/x1box/SetupWizardActivity.kt:65, 118-139, android/app/src/main/java/com/izzy2lost/x1box/XboxHddFormatter.kt:7-16, 46-50, android/app/src/main/cpp/xemu_android.cpp:822-843"
- name: eeprom.bin
required: false
path: "x1box/eeprom.bin"
config_key: "sys.files.eeprom_path"
size: 256
validation: [size]
description: "Xbox EEPROM image"
note: >-
Always pointed at x1box/eeprom.bin, a path the wizard never asks for.
Generated as XBOX_EEPROM_VERSION_R1 when it does not exist, so a dump is
needed only to carry over a console serial, region or HDD key. It is
attached through the smbus-storage device; a size other than 256 bytes,
or a generation that fails, clears autostart. Preparing Insignia and the
EEPROM editor write to it in place.
source_ref: "system/vl.c:2921-2964, 3045-3055, android/app/src/main/cpp/xemu_android.cpp:757-759, 719, android/app/src/main/cpp/xemu_settings_android.cc:246-286, android/app/src/main/java/com/izzy2lost/x1box/SettingsActivity.kt:2748-2751"
- name: xboxdash.xbe
required: false
load_from: hdd_image
path: "C/xboxdash.xbe"
description: "Retail dashboard boot executable"
note: >-
Imported to the root of partition C from the C directory of a user
dashboard tree. The import treats this name as the boot entry: when it is
absent the best scoring .xbe of the tree is copied to it, and the retail
boot counts as ready only once the name exists. The start path of the
emulator never reads partition C, and preparing Insignia finishes with a
warning when the name is missing.
source_ref: "android/app/src/main/cpp/xemu_fatx_import.c:1796-1797, 1842-1843, 1864-1911, android/app/src/main/java/com/izzy2lost/x1box/SettingsActivity.kt:2370-2401, 2436-2445, 2518, 2536-2538"
- name: msdash.xbe
required: false
load_from: hdd_image
path: "C/msdash.xbe"
description: "Retail dashboard executable kept beside the boot copy"
note: >-
Probed at the root of partition C and imported with the rest of the tree.
Its presence beside the boot XBE is one of the marks the status line
reads to call a dashboard install complete, and it is one of the names
that decide which directory of a picked tree is taken as the source root.
source_ref: "android/app/src/main/cpp/xemu_fatx_import.c:1798-1799, 1844-1845, android/app/src/main/java/com/izzy2lost/x1box/XboxInsigniaHelper.kt:13, 42-50, android/app/src/main/java/com/izzy2lost/x1box/SettingsActivity.kt:2518, 2539-2541"
- name: xbox.xtf
required: false
load_from: hdd_image
path: "C/xbox.xtf"
description: "Dashboard typeface"
note: >-
Probed at the root of partition C and imported with the rest of the tree,
alongside the xodash, audio, fonts and xboxdashdata.* directories the
root scan looks for.
source_ref: "android/app/src/main/cpp/xemu_fatx_import.c:1786-1794, 1800-1801, 1846-1847, android/app/src/main/java/com/izzy2lost/x1box/XboxInsigniaHelper.kt:12, 14-16, android/app/src/main/java/com/izzy2lost/x1box/SettingsActivity.kt:2518, 2542-2543"
- name: "<driver>.zip"
required: false
unsourceable: "third-party Vulkan driver built for one GPU family, not an emulator artefact"
description: "Replacement Vulkan driver package"
note: >-
Imported through a picker into gpu_drivers under the external files
directory, renamed after the name field of the meta.json it carries, then
unpacked whole into gpu_driver in internal storage, entries that would
escape that directory being refused. The minApi field is compared against
the device before the archive is kept. Loading is offered only when
/dev/kgsl-3d0 exists, and clearing the install directory returns the app
to the system driver.
source_ref: "android/app/src/main/java/com/izzy2lost/x1box/GpuDriverHelper.kt:15, 19-35, 41-89, 91-131, 133-136, 170-197"
- name: gamecontrollerdb.txt
required: false
bundled: true
unsourceable: "opened through the asset manager inside the package, so no file on disk reaches this load"
description: "SDL controller mapping database"
note: >-
Read from the assets of the package as the game controller subsystem
comes up and handed to SDL as a memory stream. The asset manager reads
inside the archive and the path is a constant, so there is no search
order and nothing outside the package replaces this copy; an added pad
mapping goes in through controller_map.txt instead. The revision shipped
here is 589031 bytes and is not the one other releases carry under this
name.
source_ref: "android/app/src/main/cpp/xemu_android.cpp:205-206, 236-275, 1192-1197"
- name: X1_Covers.txt
required: false
bundled: true
description: "Cover art index for the game library"
note: >-
Read from the assets and turned into a lookup from normalised game name
to a URL under the X1_Covers repository, which the library fetches and
caches per title. Only lines ending in .png are kept.
source_ref: "android/app/src/main/java/com/izzy2lost/x1box/GameLibraryActivity.kt:103, 895-935"
- name: controller_map.txt
required: false
load_from: internal_storage
description: "Extra SDL controller mappings"
note: >-
SDL builds this path from the internal storage directory of the package
when SDL_GAMECONTROLLERCONFIG_FILE is unset, which it is here, and reads
it while the game controller subsystem starts, after the mappings
compiled in. It is the one mapping file a user can add without
rebuilding the package. The SDL2 tree in thirdparty is what the build
compiles, the local checkout taking precedence over the release archive
CMake would otherwise fetch.
source_ref: "thirdparty/SDL2/src/joystick/SDL_gamecontroller.c:1873-1885, 1890-1907, android/app/src/main/cpp/CMakeLists.txt:61-72"
exclusion_note: >
Two file loads present in the tree are not reached by this build and are not
listed. hw/xbox/chihiro.c falls back to the media board ROM when no path is
given and maps a media board filesystem image beside it, but the whole driver
is filtered out of the source list, so no Chihiro machine exists here.
X1_Covers.xml ships in the assets and no code opens it, the library reading
X1_Covers.txt instead.
ref: hw/xbox/chihiro.c,
android/app/src/main/cpp/CMakeLists.txt:705,
android/app/src/main/assets/X1_Covers.xml,
android/app/src/main/java/com/izzy2lost/x1box/GameLibraryActivity.kt:901
+202
View File
@@ -0,0 +1,202 @@
emulator: XenDroid
type: standalone
core_classification: community_fork
source: "https://github.com/rfandango/XenDroid"
upstream: "https://github.com/has207/xenia-edge"
author: "rfandango"
profiled_date: "2026-08-12"
source_commit: "b70d64374f8733645e8ea63f50430165b7dbd684"
upstream_commit: "84cf209221160590768f615a0369a9c4a1456bbf"
core_version: "b70d643"
display_name: "Microsoft - Xbox 360 (XenDroid)"
cores:
- "xendroid"
- "XENDROID"
systems:
- microsoft-xbox-360
mode: standalone
notes: |
Xbox 360 emulator for Android, package xendroid.compose, arm64-v8a only.
Xenia Edge is vendored whole under emulator-core/src/main/cpp/xenia and a
Kotlin and Compose frontend replaces the desktop front end: its own windowed
app, AAudio and OpenSLES audio systems, an Android input driver, and Android
providers for the guest keyboard, the message box and disc swap. The library
recognises ISO, ZAR, GOD, extracted XEX folders and STFS containers, and the
boot path reads the file signature before mounting.
ref: emulator-core/src/main/cpp/CMakeLists.txt:30-56, 112-152,
emulator-core/src/main/cpp/xendroid_emu.cpp:333-346, 671-676,
app/src/main/java/xendroid/compose/data/GameFormat.kt:6, 26-32
Releases are tagged XenDroid-<short commit> and the version name is the git
hash handed to the build, so b70d643 is both the head of main and the current
release. version.h names canary_experimental dc561e4df, carried over from the
ax360e tree the project started as, and it does not describe the vendored
code. The Edge revision is named by the periodic merge pull request instead,
and Edge rebases its branch, so that commit is no longer reachable there.
ref: app/build.gradle:34, emulator-core/src/main/cpp/version.h:4-5,
.github/workflows/XenDroid.yml:185-187
No Xbox 360 system file is read. xboxkrnl, xam and xbdm are HLE modules
registered at startup, the XEX1 retail, XEX2 retail and XEX2 devkit keys are
constant arrays tried in turn when an image is read, and every XConfig setting
is answered from cvars and constants rather than from a flash image. When the
launched title is itself a system title the kernel resolves xam.xex, then
$flash_xam.xex, through the guest filesystem under the \SystemRoot symlink
pointing at that title's own directory.
ref: emulator-core/src/main/cpp/xenia/src/xenia/emulator.cc:421-428, 757-772,
emulator-core/src/main/cpp/xenia/src/xenia/cpu/xex_module.cc:55-63, 925-935,
emulator-core/src/main/cpp/xenia/src/xenia/kernel/xconfig.cc:89-159
The storage root is the compose external files directory of the package and is
passed as a launch argument beside the config path and the log path. content,
cache, cache0, cache1, patches and plugins hang off it, the global
configuration is xenia-canary.config.toml and per title overrides live in
config/<TITLE_ID>.config.toml. The custom driver directory sits in internal
storage instead, because the external filesystem cannot carry an executable
mapping.
ref: emulator-core/src/main/java/xendroid/compose/Application.java:14-33, 84-88,
app/src/main/java/xendroid/compose/EmulatorHostActivity.kt:231-236,
emulator-core/src/main/cpp/xendroid_emu.cpp:312-317, 355-381
479 game patches ship inside the APK, synced at build time from the
xenia-canary game-patches submodule pinned at 3553a5ae. The patch database
reads the patches directory only, so a bundled patch reaches the emulator once
the user toggles it, which writes the asset out under the same name.
ref: app/build.gradle:12-19,
app/src/main/java/xendroid/compose/patches/PatchAssets.kt:17-23,
app/src/main/java/xendroid/compose/patches/PatchStore.kt:23-33,
emulator-core/src/main/cpp/xenia/src/xenia/patcher/patch_db.cc:34-60
ES-DE finds the emulator by the xendroid.compose/.EmulatorHostActivity package
rule and hands the game over as the intent data URI.
ref: app/src/main/AndroidManifest.xml:54-73, docs/frontend-integration.md
files:
- name: "<driver>.zip"
required: false
config_key: "Vulkan|vulkan_lib_path"
unsourceable: "third-party Vulkan driver built for one GPU family, not an emulator artefact"
description: "Replacement Vulkan driver package"
note: >-
Imported through a picker restricted to application/zip. The archive is
read whole, meta.json names the library to keep, and a single .so is taken
instead when no meta.json is present; the .so files and meta.json are
unpacked into a directory named after the archive, in internal storage.
The configured path is read before the instance is created and opened
through adrenotools when the file exists, otherwise the system libvulkan.so
is used. The row is hidden on devices without /dev/kgsl-3d0.
source_ref: "app/src/main/java/xendroid/compose/ui/settings/SettingRows.kt:175-200, app/src/main/java/xendroid/compose/settings/SettingsRepository.kt:34-35, 140, emulator-core/src/main/java/xendroid/compose/Utils.java:164-236, emulator-core/src/main/java/xendroid/compose/Application.java:21-24, emulator-core/src/main/cpp/xenia/src/xenia/ui/vulkan/vulkan_instance.cc:49, 168-192, 203"
- name: "<font>.ttf"
required: false
config_key: "UI|custom_font_path"
unsourceable: "any TrueType face the user points the setting at, with no name or version the code expects"
description: "Replacement face for the overlay text"
note: >-
Loaded when the configured path exists, over the glyph ranges the atlas is
built with. A path that does not resolve, or a face that fails to build,
leaves the embedded Inter face in place, so the absence is covered.
source_ref: "emulator-core/src/main/cpp/xenia/src/xenia/ui/imgui_drawer.cc:39-44, 353-366, 367-376"
- name: "<sound>.wav"
required: false
config_key: "UI|achievement_sound_path"
unsourceable: "any sound file the user points the setting at, with no name or version the code expects"
description: "Sound played when an achievement unlocks"
note: >-
Read through miniaudio, which accepts WAV, MP3, OGG and FLAC. The engine is
built the first time an achievement fires, and an empty or missing path
leaves the notification silent. Config written under the older key
General|notification_sound_path is carried to this cvar when the file is
read, and that is the key the shipped template still carries.
source_ref: "emulator-core/src/main/cpp/xenia/src/xenia/ui/audio_helper.cc:21-24, 38-80, 97-101, emulator-core/src/main/cpp/xenia/src/xenia/kernel/xam/achievement_manager.cc:163-166, emulator-core/src/main/cpp/xenia/src/xenia/config.cc:174-190, emulator-core/src/main/cpp/xenia/src/xenia/ui/config_helpers.h:47"
- name: "<title_id> - <title>.patch.toml"
required: false
bundled: true
config_key: "General|apply_patches"
description: "Memory patch set for one title"
note: >-
Read from the patches directory under the storage root, keeping names that
open with eight hexadecimal digits and close with .patch.toml. The title id
and title name fields and a hash node are mandatory, the file is dropped
without them, and each entry of the patch array is applied only when its
is_enabled flag is set and the module hash matches. Patching is on by
default.
source_ref: "emulator-core/src/main/cpp/xenia/src/xenia/patcher/patch_db.h:124-125, emulator-core/src/main/cpp/xenia/src/xenia/patcher/patch_db.cc:34-60, 63-105, emulator-core/src/main/cpp/xenia/src/xenia/patcher/patcher.cc:22-37, emulator-core/src/main/cpp/xenia/src/xenia/emulator.cc:415"
- name: plugins.toml
required: false
config_key: "General|allow_plugins"
unsourceable: "per-title manifest written by whoever authors the mod, with no distributed form"
description: "Plugin manifest for one title"
note: >-
Read from plugins/<TITLE_ID>/ under the storage root, where the directory
name is eight hexadecimal digits. Each entry of the plugin array needs a
hash node, and an entry without one is skipped. Plugin loading is off by
default, so nothing under plugins is scanned until it is turned on.
source_ref: "emulator-core/src/main/cpp/xenia/src/xenia/patcher/plugin_loader.cc:16-21, 27-37, 40-56, 58-125, emulator-core/src/main/cpp/xenia/src/xenia/emulator.cc:431-432"
- name: "<plugin>.xex"
required: false
unsourceable: "homebrew module built for one title, distributed with the mod it belongs to"
description: "Plugin module named by a plugin manifest"
note: >-
The title directory is mounted as the plugins device and each enabled entry
whose hash matches the running module is loaded as a user module on its own
thread.
source_ref: "emulator-core/src/main/cpp/xenia/src/xenia/patcher/plugin_loader.cc:175-233, 235-252, emulator-core/src/main/cpp/xenia/src/xenia/emulator.cc:2625-2630"
- name: Account
required: false
load_from: content_dir
path: "content/<XUID>/FFFE07D1/00010000/<XUID>/Account"
unsourceable: "per-user blob the emulator encrypts with the console key on first run"
description: "Encrypted profile account blob"
note: >-
A 0x10 hash, an 8 byte confounder and an encrypted X_XAMACCOUNTINFO. Read
from the profile directory when the content tree is enumerated and from the
mounted profile when a XUID is logged in, decrypted with the retail key
first and the devkit key second, against the HMAC the first sixteen bytes
carry. The frontend creates one for the gamertag XenDroid on first run when
the tree holds none, and writes its XUID to the slot 0 setting.
source_ref: "emulator-core/src/main/cpp/xenia/src/xenia/kernel/xam/profile_standalone.cc:24-52, 72-99, 129-141, emulator-core/src/main/cpp/xenia/src/xenia/kernel/xam/profile_manager.cc:256-296, app/src/main/java/xendroid/compose/core/ProfileBootstrap.kt:13-28, app/src/main/java/xendroid/compose/core/ProfilePaths.kt:6-13"
exclusion_note: >
The file loads present in the vendored tree that this build does not reach are
not listed. tahoma.ttf and msgothic.ttc are read by the Windows font paths
only, and the two fontconfig matches are compiled out by
XE_PLATFORM_LINUX && !(XE_PLATFORM_ANDROID || XE_PLATFORM_xendroid), because
platform.h defines XE_PLATFORM_xendroid and XE_PLATFORM_LINUX for this target
and leaves XE_PLATFORM_ANDROID commented out. gamecontrollerdb.txt belongs to the SDL
input driver, and xenia-hid-sdl is absent from the link list, which carries
xenia-hid-nop and the fork's own Android driver. portable.txt is read by
xenia_main.cc, which is not compiled, the application supplying its own
windowed app. The profile picture the gamercard dialog reads through
ReadPngFromFile is never reached: the Android file picker returns false without
showing anything, so no path is ever selected. librenderdoc.so is opened with
RTLD_NOLOAD, which returns a handle only when the library is already mapped and
never reads the file. Edge's in-binary patch bundle, its game compatibility
bundle and its game title database are packed from build/data_repos, which
xenia-build.py fetches and the Gradle build never runs, so the bundle compiled
in is empty and the APK assets are the only patch source; the locale bundle is
guarded off when the CMake system name is Android. Two profile files sit beside
the Account and are not listed: tile_32.png is written and never read back, and
tile_64.png is written by the frontend from a picture the user picks and read
only to draw the avatar, the core testing its existence and nothing more.
ref: emulator-core/src/main/cpp/xenia/src/xenia/ui/imgui_drawer.cc:389-405, 418-465, 474-490, 500-536,
emulator-core/src/main/cpp/xenia/src/xenia/base/platform.h:34-40,
emulator-core/src/main/cpp/xenia/src/xenia/hid/sdl/CMakeLists.txt:7-8,
emulator-core/src/main/cpp/CMakeLists.txt:112-152,
emulator-core/src/main/cpp/xenia/src/xenia/app/xenia_main.cc:95-99,
emulator-core/src/main/cpp/xenia/src/xenia/app/xenia_main.cc:561,
emulator-core/src/main/cpp/xenia/src/xenia/kernel/xam/ui/gamercard_ui.cc:339-368,
emulator-core/src/main/cpp/xenia/src/xenia/ui/file_picker_android.cc:27-34,
emulator-core/src/main/cpp/xenia/src/xenia/ui/renderdoc_api.cc:33-41,
emulator-core/src/main/cpp/xenia/src/xenia/patcher/CMakeLists.txt:6-7,
emulator-core/src/main/cpp/xenia/src/xenia/app/CMakeLists.txt:213-219,
emulator-core/src/main/cpp/xenia/src/xenia/ui/CMakeLists.txt:66-84,
emulator-core/src/main/cpp/xenia/tools/build/embed_bundle.py:55-57,
app/src/main/java/xendroid/compose/ui/profile/ProfileManagerViewModel.kt:173-181,
emulator-core/src/main/cpp/xenia/src/xenia/kernel/xam/profile_standalone.cc:140-141
+90
View File
@@ -0,0 +1,90 @@
emulator: XeniOS
type: standalone
core_classification: community_fork
source: "https://github.com/xenios-jp/XeniOS"
upstream: "https://github.com/has207/xenia-edge"
profiled_date: "2026-08-12"
source_commit: "87b176a078c316fde3adf67a217f0c44615b0e0d"
upstream_commit: "07021f019cf55105bc26c0474e0b0835808353e2"
core_version: "2.0.1"
display_name: "Microsoft - Xbox 360 (XeniOS)"
cores:
- "xenios"
- "XENIOS"
systems:
- microsoft-xbox-360
mode: standalone
notes: |
Xbox 360 emulator for macOS and iOS, forked from Xenia Edge by xenios-jp and
published as xenios_macos_apple_silicon.dmg, xenios_macos_intel.dmg,
xenios_macos_universal.dmg and xenios_ios_iphone_ipad.ipa. The 2.0.1 disk
image holds a single bundle, Xenia-edge.app, carrying the executable, an
icon, a compiled asset catalog and two dylibs under Contents/Frameworks.
Rendering runs on Metal. Guest DXBC is converted to DXIL through
libdxilconv.dylib, built from the fork's own DirectX Shader Compiler branch,
then to Metal IR through Apple's Metal Shader Converter
(libmetalirconverter.dylib), which the build requires present before it will
configure. Both are linked as imported shared libraries and copied into the
bundle before it is signed (third_party/CMakeLists.txt:432-448, 489-579,
src/xenia/app/CMakeLists.txt:347-363, 371-378), so the code calls IRCompilerCreate
and DxcCreateInstance as ordinary symbols and never names either file
(gpu/metal/metal_shader_converter.cc:83, gpu/metal/dxbc_to_dxil_converter.cc:103).
MoltenVK is statically linked and its entry points resolve as real symbols,
so the Vulkan backend loads no loader library
(ui/vulkan/vulkan_instance.cc:30-33, 81-82).
No Xbox 360 system file is read. xboxkrnl, xam and xbdm are C++ HLE modules
registered at startup (emulator.cc:425-427), the XEX1 and XEX2 retail keys
and the zeroed devkit key are constexpr arrays in the binary
(cpu/xex_module.cc:55-63, used at 344 and 503), and every XConfig setting is
assembled from cvars and constants by BuildSetting, in a file that makes no
filesystem call at all (kernel/xconfig.cc:87-246). Launching a system title
symlinks \SystemRoot to that title's own mount and resolves xam.xex, then
$flash_xam.xex, through the guest filesystem (emulator.cc:744-762): a
companion module inside the dump the user launched, not a host lookup.
The fork's data ships inside the executable. assets/font and assets/icon are
linked in by xe_embed_binary_assets and the 33 assets/locale catalogues are
compiled to .mo at configure time and bundled, with no .mo written beside the
binary (ui/CMakeLists.txt:55-58, 64-83). The UI font is read from that buffer
with AddFontFromMemoryTTF (ui/imgui_drawer.cc:367-377), and xe::EmbeddedBundle
decodes the SDL controller mappings (hid/sdl/sdl_input_driver.cc:148-165), the
canary game patches (patcher/patch_db.cc:303-318) and the canary.json and
stable.json compatibility lists (app/game_compat_db.cc:65-79).
Three cvars accept a file and name none by default, so nothing is expected at
a fixed path: custom_font_path falls back to the embedded font
(ui/imgui_drawer.cc:39-44, 353-377), mappings_file to the embedded controller
DB (hid/sdl/sdl_input_driver.cc:35-39, 148-152), achievement_sound_path leaves
the achievement sound silent (ui/audio_helper.cc:21-25, 44-48). Each carries an
UPDATE_from_path rule that clears the earlier default out of an existing config.
Everything under the storage root is written by the emulator or dropped in by
the user: xenia-edge.config.toml and per-title config/<title id>.config.toml
(config.cc:44-52), patches/*.patch.toml read on top of the embedded set
(patcher/patch_db.cc:29-60, app/xenia_main_ios.mm:275-300), plugins/<title id>/plugins.toml
behind allow_plugins, which defaults false (patcher/plugin_loader.cc:16-18, 40-62),
content, cache_host and the per-module executable_addr_flags.bin analysis cache
(app/xenia_main.cc:588-613, cpu/xex_module.cc:1336-1343). portable.txt next to
the executable keeps the storage root there instead of the user folder
(app/xenia_main.cc:556-570). On iOS the touch layouts live as
Documents/touch-layouts/<id>.toml, written by the layout editor
(ui/ios/touch/touch_layout_store_ios.mm:117-139).
files: []
exclusion_note: >
XeniOS emulates the Xbox 360 by high-level emulation and reads no BIOS,
firmware, NAND image, flash dump or keyvault at any point: the kernel, XAM
and XBDM are compiled-in modules, the XEX AES keys are constant arrays and
XConfig is synthesised. Its own data (UI font, icons, locale catalogues, SDL
controller mappings, game patches, compatibility lists) is compressed into
the executable through xe_embed_binary_assets and xe_embed_compressed_bundle,
so none of it exists as a file beside the binary. The three cvars that accept
a path default to empty and fall back to those embedded copies. The two
dylibs under Contents/Frameworks, libmetalirconverter.dylib and
libdxilconv.dylib, are shader translation components linked at build time and
resolved by the loader through @rpath; no code path names them, and they are
obtained by the same download that provides the executable.