OBJS += frontend/libpicofe/linux/in_evdev.o
OBJS += frontend/plat_pandora.o frontend/plat_omap.o
frontend/main.o frontend/menu.o: CFLAGS += -include frontend/pandora/ui_feat.h
+frontend/libpicofe/linux/plat.o: CFLAGS += -DPANDORA
USE_PLUGIN_LIB = 1
USE_FRONTEND = 1
endif
void bgr888_to_rgb565(void *dst, const void *src, int bytes);
void rgb888_to_rgb565(void *dst, const void *src, int bytes);
+void bgr555_to_rgb565_b(void *dst, const void *src, int bytes,
+ int brightness2k); // 0-0x0800
+
void bgr_to_uyvy_init(void);
void rgb565_to_uyvy(void *d, const void *s, int pixels);
void bgr555_to_uyvy(void *d, const void *s, int pixels);
.text
.align 2
-FUNCTION(bgr555_to_rgb565):
+FUNCTION(bgr555_to_rgb565): @ dst, src, bytes
pld [r1]
mov r3, #0x07c0
vdup.16 q15, r3
0:
pld [r1, #64*2]
vldmia r1!, {q0-q3}
- vshl.u16 q4, q0, #11
- vshl.u16 q5, q1, #11
- vshl.u16 q6, q2, #11
- vshl.u16 q7, q3, #11
- vsri.u16 q4, q0, #10
- vsri.u16 q5, q1, #10
- vsri.u16 q6, q2, #10
- vsri.u16 q7, q3, #10
- vshl.u16 q0, q0, #1
- vshl.u16 q1, q1, #1
- vshl.u16 q2, q2, #1
- vshl.u16 q3, q3, #1
- vbit q4, q0, q15
- vbit q5, q1, q15
- vbit q6, q2, q15
- vbit q7, q3, q15
- vstmia r0!, {q4-q7}
+ vshl.u16 q8, q0, #11
+ vshl.u16 q9, q1, #11
+ vshl.u16 q10, q2, #11
+ vshl.u16 q11, q3, #11
+ vsri.u16 q8, q0, #10
+ vsri.u16 q9, q1, #10
+ vsri.u16 q10, q2, #10
+ vsri.u16 q11, q3, #10
+ vshl.u16 q0, q0, #1
+ vshl.u16 q1, q1, #1
+ vshl.u16 q2, q2, #1
+ vshl.u16 q3, q3, #1
+ vbit q8, q0, q15
+ vbit q9, q1, q15
+ vbit q10, q2, q15
+ vbit q11, q3, q15
+ vstmia r0!, {q8-q11}
subs r2, r2, #64
bge 0b
bxlt lr
@ very rare
- vld1.16 d0, [r1]!
+ vld1.16 {d0}, [r1]!
vshl.u16 d1, d0, #11
vshl.u16 d2, d0, #1
vsri.u16 d1, d0, #10
vbit d1, d2, d30
- vst1.16 d1, [r0]!
+ vst1.16 {d1}, [r0]!
+ bx lr
+
+
+@ note: may overflow source
+FUNCTION(bgr555_to_rgb565_b): @ dst, src, bytes, int brightness2k // 0-0x0800
+ pld [r1]
+ vdup.16 q15, r3
+ vpush {q4-q7}
+ mov r3, #0x1f
+ vdup.16 q14, r3
+0:
+ pld [r1, #64*2]
+ vldmia r1!, {q0-q3}
+ vand.u16 q8, q0, q14
+ vand.u16 q9, q1, q14
+ vand.u16 q10, q2, q14
+ vand.u16 q11, q3, q14
+ vmul.u16 q4, q8, q15
+ vmul.u16 q5, q9, q15
+ vmul.u16 q6, q10, q15
+ vmul.u16 q7, q11, q15
+
+ vshr.u16 q8, q0, #5
+ vshr.u16 q9, q1, #5
+ vshr.u16 q10, q2, #5
+ vshr.u16 q11, q3, #5
+ vand.u16 q8, q14
+ vand.u16 q9, q14
+ vand.u16 q10, q14
+ vand.u16 q11, q14
+ vmul.u16 q8, q15
+ vmul.u16 q9, q15
+ vmul.u16 q10, q15
+ vmul.u16 q11, q15
+ vsri.u16 q4, q8, #5
+ vsri.u16 q5, q9, #5
+ vsri.u16 q6, q10, #5
+ vsri.u16 q7, q11, #5
+
+ vshr.u16 q8, q0, #10
+ vshr.u16 q9, q1, #10
+ vshr.u16 q10, q2, #10
+ vshr.u16 q11, q3, #10
+ vand.u16 q8, q14
+ vand.u16 q9, q14
+ vand.u16 q10, q14
+ vand.u16 q11, q14
+ vmul.u16 q8, q15
+ vmul.u16 q9, q15
+ vmul.u16 q10, q15
+ vmul.u16 q11, q15
+ vsri.u16 q4, q8, #11
+ vsri.u16 q5, q9, #11
+ vsri.u16 q6, q10, #11
+ vsri.u16 q7, q11, #11
+
+ subs r2, r2, #64
+ ble 1f
+ vstmia r0!, {q4-q7}
+ b 0b
+
+1:
+ blt 0f
+ vstmia r0!, {q4-q7}
+ b btr16b_end
+0:
+ subs r2, r2, #8
+ blt btr16b_end
+ vst1.16 {q4}, [r0]!
+ subs r2, r2, #8
+ blt btr16b_end
+ vst1.16 {q5}, [r0]!
+ subs r2, r2, #8
+ blt btr16b_end
+ vst1.16 {q6}, [r0]!
+ subs r2, r2, #8
+ blt btr16b_end
+ vst1.16 {q7}, [r0]!
+
+btr16b_end:
+ vpop {q4-q7}
bx lr
-FUNCTION(bgr888_to_rgb888):
+FUNCTION(bgr888_to_rgb888): @ dst, src, bytes
pld [r1]
@ r2 /= 48
mov r2, r2, lsr #4
bx lr
-FUNCTION(bgr888_to_rgb565):
+FUNCTION(bgr888_to_rgb565): @ dst, src, bytes
pld [r1]
@ r2 /= 48
mov r2, r2, lsr #4
bx lr
-FUNCTION(rgb888_to_rgb565):
+FUNCTION(rgb888_to_rgb565): @ dst, src, bytes
pld [r1]
@ r2 /= 48
mov r2, r2, lsr #4
-Subproject commit d1453cf7e6d5d6758cc5d72c6d3af7d37156bf72
+Subproject commit 515ac0b9d2c4d45a465335d54b8c49830914fcea
{
memset(info, 0, sizeof(*info));
info->library_name = "PCSX-ReARMed";
- info->library_version = "r19";
+ info->library_version = "r20";
info->valid_extensions = "bin|cue|img|mdf|pbp|toc|cbn|m3u";
info->need_fullpath = true;
}
/* savestates */
size_t retro_serialize_size(void)
{
- // it's currently 4380651 bytes, but have some reserved for future
- return 0x430000;
+ // it's currently 4380651-4397047 bytes,
+ // but have some reserved for future
+ return 0x440000;
}
struct save_fp {
/*
- * (C) Gražvydas "notaz" Ignotas, 2010-2013
+ * (C) Gražvydas "notaz" Ignotas, 2010-2014
*
* This work is licensed under the terms of any of these licenses
* (at your option):
MA_OPT_SWFILTER,
MA_OPT_GAMMA,
MA_OPT_VOUT_MODE,
+ MA_OPT_SCANLINES,
+ MA_OPT_SCANLINE_LEVEL,
} menu_id;
static int last_vout_w, last_vout_h, last_vout_bpp;
static char last_selected_fname[MAXPATHLEN];
static int config_save_counter, region, in_type_sel1, in_type_sel2;
static int psx_clock;
-static int memcard1_sel, memcard2_sel;
+static int memcard1_sel = -1, memcard2_sel = -1;
+extern int g_autostateld_opt;
int g_opts, g_scaler, g_gamma = 100;
+int scanlines, scanline_level = 20;
int soft_scaling, analog_deadzone; // for Caanoo
int soft_filter;
struct stat64 statf;
FILE *f;
+ if (count <= 1)
+ return count;
+
for (i = 1; i < count; i++) {
if (namelist[i] == NULL || namelist[i]->d_type == DT_DIR)
continue;
analog_deadzone = 50;
soft_scaling = 1;
soft_filter = 0;
+ scanlines = 0;
+ scanline_level = 20;
plat_target.vout_fullscreen = 0;
psx_clock = DEFAULT_PSX_CLOCK;
CE_CONFIG_VAL(VSyncWA),
CE_CONFIG_VAL(Cpu),
CE_INTVAL(region),
- CE_INTVAL_V(g_scaler, 2),
+ CE_INTVAL_V(g_scaler, 3),
CE_INTVAL(g_gamma),
CE_INTVAL(g_layer_x),
CE_INTVAL(g_layer_y),
CE_INTVAL(g_layer_w),
CE_INTVAL(g_layer_h),
CE_INTVAL(soft_filter),
+ CE_INTVAL(scanlines),
+ CE_INTVAL(scanline_level),
CE_INTVAL(plat_target.vout_method),
CE_INTVAL(plat_target.hwfilter),
CE_INTVAL(plat_target.vout_fullscreen),
CE_INTVAL(in_type_sel1),
CE_INTVAL(in_type_sel2),
CE_INTVAL(analog_deadzone),
+ CE_INTVAL(memcard1_sel),
+ CE_INTVAL(memcard2_sel),
+ CE_INTVAL(g_autostateld_opt),
CE_INTVAL_N("adev0_is_nublike", in_adev_is_nublike[0]),
CE_INTVAL_N("adev1_is_nublike", in_adev_is_nublike[1]),
CE_INTVAL_V(frameskip, 3),
if (strcmp(Config.Spu, spu_plugins[i]) == 0)
{ spu_plugsel = i; break; }
+ // memcard selections
+ char mcd1_old[sizeof(Config.Mcd1)];
+ char mcd2_old[sizeof(Config.Mcd2)];
+ strcpy(mcd1_old, Config.Mcd1);
+ strcpy(mcd2_old, Config.Mcd2);
+
+ if ((unsigned int)memcard1_sel < ARRAY_SIZE(memcards)) {
+ if (memcard1_sel == 0)
+ strcpy(Config.Mcd1, "none");
+ else if (memcards[memcard1_sel] != NULL)
+ snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s",
+ MEMCARD_DIR, memcards[memcard1_sel]);
+ }
+ if ((unsigned int)memcard2_sel < ARRAY_SIZE(memcards)) {
+ if (memcard2_sel == 0)
+ strcpy(Config.Mcd2, "none");
+ else if (memcards[memcard2_sel] != NULL)
+ snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s",
+ MEMCARD_DIR, memcards[memcard2_sel]);
+ }
+ if (strcmp(mcd1_old, Config.Mcd1) || strcmp(mcd2_old, Config.Mcd2))
+ LoadMcds(Config.Mcd1, Config.Mcd2);
+
return ret;
}
// ------------ gfx options menu ------------
-static const char *men_scaler[] = { "1x1", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL };
+static const char *men_scaler[] = {
+ "1x1", "integer scaled 2x", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL
+};
static const char *men_soft_filter[] = { "None",
#ifdef __ARM_NEON__
"scale2x", "eagle2x",
#endif
NULL };
static const char *men_dummy[] = { NULL };
+static const char h_scaler[] = "int. 2x - scales w. or h. 2x if it fits on screen\n"
+ "int. 4:3 - uses integer if possible, else fractional";
static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
"using d-pad or move it using R+d-pad";
static const char h_overlay[] = "Overlay provides hardware accelerated scaling";
static const char h_soft_filter[] = "Works only if game uses low resolution modes";
+static const char h_scanline_l[] = "Scanline brightness, 0-100%";
static const char h_gamma[] = "Gamma/brightness adjustment (default 100)";
static int menu_loop_cscaler(int id, int keys)
static menu_entry e_menu_gfx_options[] =
{
- mee_enum ("Scaler", MA_OPT_VARSCALER, g_scaler, men_scaler),
+ mee_enum_h ("Scaler", MA_OPT_VARSCALER, g_scaler, men_scaler, h_scaler),
mee_enum ("Video output mode", MA_OPT_VOUT_MODE, plat_target.vout_method, men_dummy),
mee_onoff ("Software Scaling", MA_OPT_SCALER2, soft_scaling, 1),
mee_enum ("Hardware Filter", MA_OPT_HWFILTER, plat_target.hwfilter, men_dummy),
mee_enum_h ("Software Filter", MA_OPT_SWFILTER, soft_filter, men_soft_filter, h_soft_filter),
+#ifdef __ARM_NEON__
+ mee_onoff ("Scanlines", MA_OPT_SCANLINES, scanlines, 1),
+ mee_range_h ("Scanline brightness", MA_OPT_SCANLINE_LEVEL, scanline_level, 0, 100, h_scanline_l),
+#endif
mee_range_h ("Gamma adjustment", MA_OPT_GAMMA, g_gamma, 1, 200, h_gamma),
// mee_onoff ("Vsync", 0, vsync, 1),
mee_cust_h ("Setup custom scaler", MA_OPT_VARSCALER_C, menu_loop_cscaler, NULL, h_cscaler),
"PCSX4ALL plugin by PCSX4ALL team\n"
" Chui, Franxis, Unai\n\n"
"integration, optimization and\n"
- " frontend (C) 2010-2012 notaz\n";
+ " frontend (C) 2010-2014 notaz\n";
static int reset_game(void)
{
static int run_cd_image(const char *fname)
{
+ int autoload_state = g_autostateld_opt;
+
ready_to_go = 0;
reload_plugins(fname);
emu_on_new_cd(1);
ready_to_go = 1;
+ if (autoload_state) {
+ unsigned int newest = 0;
+ int time, slot, newest_slot = -1;
+
+ for (slot = 0; slot < 10; slot++) {
+ if (emu_check_save_file(slot, &time)) {
+ if ((unsigned int)time > newest) {
+ newest = time;
+ newest_slot = slot;
+ }
+ }
+ }
+
+ if (newest_slot >= 0) {
+ lprintf("autoload slot %d\n", newest_slot);
+ emu_load_state(newest_slot);
+ }
+ else {
+ lprintf("no save to autoload.\n");
+ }
+ }
+
return 0;
}
enum g_scaler_opts {
SCALE_1_1,
+ SCALE_2_2,
SCALE_4_3,
SCALE_4_3v2,
SCALE_FULLSCREEN,
};
extern int g_opts, g_scaler, g_gamma;
+extern int scanlines, scanline_level;
extern int soft_scaling, analog_deadzone;
extern int soft_filter;
vout_fbdev_wait_vsync(layer_fb);
}
-void *plat_gvideo_set_mode(int *w, int *h, int *bpp)
+void *plat_gvideo_set_mode(int *w_in, int *h_in, int *bpp)
{
int l = 0, r = 0, t = 0, b = 0;
+ int w = *w_in, h = *h_in;
void *buf;
- if (g_scaler == SCALE_1_1) {
- if (*w > g_menuscreen_w)
- l = r = (*w - g_menuscreen_w) / 2;
- if (*h > g_menuscreen_h)
- t = b = (*h - g_menuscreen_h) / 2;
+ if (g_scaler == SCALE_1_1 || g_scaler == SCALE_2_2) {
+ if (w > g_menuscreen_w) {
+ l = r = (w - g_menuscreen_w) / 2;
+ w -= l + r;
+ }
+ if (h > g_menuscreen_h) {
+ t = b = (h - g_menuscreen_h) / 2;
+ h -= t + b;
+ }
}
vout_fbdev_clear(layer_fb);
- buf = vout_fbdev_resize(layer_fb, *w, *h, *bpp,
+ buf = vout_fbdev_resize(layer_fb, w, h, *bpp,
l, r, t, b, 3);
omap_enable_layer(1);
g_layer_w = w; g_layer_h = h;
break;
+ case SCALE_2_2:
+ g_layer_w = w; g_layer_h = h;
+ if (w * 2 <= g_menuscreen_w)
+ g_layer_w = w * 2;
+ if (h * 2 <= g_menuscreen_h)
+ g_layer_h = h * 2;
+ break;
+
case SCALE_4_3v2:
if (h > g_menuscreen_h || (240 < h && h <= 360))
goto fractional_4_3;
neon_eagle2x_16_16(src, (void *)dest, w,
stride * 2, dstride * 2, h);
}
+ else if (scanlines != 0 && scanline_level != 100)
+ {
+ int l = scanline_level * 2048 / 100;
+
+ for (; h1 >= 2; h1 -= 2)
+ {
+ bgr555_to_rgb565(dest, src, w * 2);
+ dest += dstride * 2, src += stride;
+
+ bgr555_to_rgb565_b(dest, src, w * 2, l);
+ dest += dstride * 2, src += stride;
+ }
+ }
#endif
else
{
SysPrintf("cdrom: fixing up old savestate\n");
cdr.Reg2 = 7;
}
+ // also did not save Attenuator..
+ if ((cdr.AttenuatorLeftToLeft | cdr.AttenuatorLeftToRight
+ | cdr.AttenuatorRightToLeft | cdr.AttenuatorRightToRight) == 0)
+ {
+ cdr.AttenuatorLeftToLeft = cdr.AttenuatorRightToRight = 0x80;
+ }
}
}
f = SaveFuncs.open(file, "wb");
if (f == NULL) return -1;
- new_dyna_save();
+ new_dyna_before_save();
SaveFuncs.write(f, (void *)PcsxHeader, 32);
SaveFuncs.write(f, (void *)&SaveVersion, sizeof(u32));
psxHwFreeze(f, 1);
psxRcntFreeze(f, 1);
mdecFreeze(f, 1);
+ new_dyna_freeze(f, 1);
SaveFuncs.close(f);
psxHwFreeze(f, 0);
psxRcntFreeze(f, 0);
mdecFreeze(f, 0);
+ new_dyna_freeze(f, 0);
SaveFuncs.close(f);
- new_dyna_restore();
return 0;
}
MTC0(reg, val);
}
-void new_dyna_save(void)
+void new_dyna_before_save(void)
{
psxRegs.interrupt &= ~(1 << PSXINT_RCNT); // old savestate compat
psxRegs.interrupt |= 1 << PSXINT_RCNT;
}
-void new_dyna_restore(void)
+static void new_dyna_restore(void)
{
int i;
for (i = 0; i < PSXINT_COUNT; i++)
new_dyna_pcsx_mem_load_state();
}
+void new_dyna_freeze(void *f, int mode)
+{
+ const char header_save[8] = "ariblks";
+ uint32_t addrs[1024 * 4];
+ int32_t size = 0;
+ int bytes;
+ char header[8];
+
+ if (mode != 0) { // save
+ size = new_dynarec_save_blocks(addrs, sizeof(addrs));
+ if (size == 0)
+ return;
+
+ SaveFuncs.write(f, header_save, sizeof(header_save));
+ SaveFuncs.write(f, &size, sizeof(size));
+ SaveFuncs.write(f, addrs, size);
+ }
+ else {
+ new_dyna_restore();
+
+ bytes = SaveFuncs.read(f, header, sizeof(header));
+ if (bytes != sizeof(header) || strcmp(header, header_save)) {
+ if (bytes > 0)
+ SaveFuncs.seek(f, -bytes, SEEK_CUR);
+ return;
+ }
+ SaveFuncs.read(f, &size, sizeof(size));
+ if (size <= 0)
+ return;
+ if (size > sizeof(addrs)) {
+ bytes = size - sizeof(addrs);
+ SaveFuncs.seek(f, bytes, SEEK_CUR);
+ size = sizeof(addrs);
+ }
+ bytes = SaveFuncs.read(f, addrs, size);
+ if (bytes != size)
+ return;
+
+ new_dynarec_load_blocks(addrs, size);
+ }
+
+ //printf("drc: %d block info entries %s\n", size/8, mode ? "saved" : "loaded");
+}
+
/* GTE stuff */
void *gte_handlers[64];
void new_dyna_pcsx_mem_reset(void) {}
void new_dyna_pcsx_mem_load_state(void) {}
void new_dyna_pcsx_mem_shutdown(void) {}
+int new_dynarec_save_blocks(void *save, int size) { return 0; }
+void new_dynarec_load_blocks(const void *save, int size) {}
#endif
#ifdef DRC_DBG
1:
movs r4, r5
beq 2f
- ldr r3, [r5]
- ldr r5, [r4, #12]
+ ldr r3, [r5] /* ll_entry .vaddr */
+ ldrd r4, r5, [r4, #8] /* ll_entry .next, .addr */
teq r3, r0
bne 1b
- ldr r3, [r4, #4]
- ldr r4, [r4, #8]
- tst r3, r3
- bne 1b
teq r4, r6
moveq pc, r4 /* Stale i-cache */
mov r8, r4
u_int waswritten; // MIPS regs that were used as store base before
};
+// note: asm depends on this layout
struct ll_entry
{
u_int vaddr;
- u_int reg32;
+ u_int reg_sv_flags;
void *addr;
struct ll_entry *next;
};
u_int start;
u_int *source;
- u_int pagelimit;
char insn[MAXBLOCK][10];
u_char itype[MAXBLOCK];
u_char opcode[MAXBLOCK];
int is_delayslot;
int cop1_usable;
u_char *out;
- struct ll_entry *jump_in[4096];
+ struct ll_entry *jump_in[4096] __attribute__((aligned(16)));
struct ll_entry *jump_out[4096];
struct ll_entry *jump_dirty[4096];
u_int hash_table[65536][4] __attribute__((aligned(16)));
//printf("TRACE: count=%d next=%d (get_addr %x,page %d)\n",Count,next_interupt,vaddr,page);
head=jump_in[page];
while(head!=NULL) {
- if(head->vaddr==vaddr&&head->reg32==0) {
+ if(head->vaddr==vaddr) {
//printf("TRACE: count=%d next=%d (get_addr match %x: %x)\n",Count,next_interupt,vaddr,(int)head->addr);
int *ht_bin=hash_table[((vaddr>>16)^vaddr)&0xFFFF];
ht_bin[3]=ht_bin[1];
}
head=jump_dirty[vpage];
while(head!=NULL) {
- if(head->vaddr==vaddr&&head->reg32==0) {
+ if(head->vaddr==vaddr) {
//printf("TRACE: count=%d next=%d (get_addr match dirty %x: %x)\n",Count,next_interupt,vaddr,(int)head->addr);
// Don't restore blocks which are about to expire from the cache
if((((u_int)head->addr-(u_int)out)<<(32-TARGET_SIZE_2))>0x60000000+(MAX_OUTPUT_BLOCK_SIZE<<(32-TARGET_SIZE_2)))
return get_addr(vaddr);
}
-void *get_addr_32(u_int vaddr,u_int flags)
-{
-#ifdef FORCE32
- return get_addr(vaddr);
-#else
- //printf("TRACE: count=%d next=%d (get_addr_32 %x,flags %x)\n",Count,next_interupt,vaddr,flags);
- int *ht_bin=hash_table[((vaddr>>16)^vaddr)&0xFFFF];
- if(ht_bin[0]==vaddr) return (void *)ht_bin[1];
- if(ht_bin[2]==vaddr) return (void *)ht_bin[3];
- u_int page=get_page(vaddr);
- u_int vpage=get_vpage(vaddr);
- struct ll_entry *head;
- head=jump_in[page];
- while(head!=NULL) {
- if(head->vaddr==vaddr&&(head->reg32&flags)==0) {
- //printf("TRACE: count=%d next=%d (get_addr_32 match %x: %x)\n",Count,next_interupt,vaddr,(int)head->addr);
- if(head->reg32==0) {
- int *ht_bin=hash_table[((vaddr>>16)^vaddr)&0xFFFF];
- if(ht_bin[0]==-1) {
- ht_bin[1]=(int)head->addr;
- ht_bin[0]=vaddr;
- }else if(ht_bin[2]==-1) {
- ht_bin[3]=(int)head->addr;
- ht_bin[2]=vaddr;
- }
- //ht_bin[3]=ht_bin[1];
- //ht_bin[2]=ht_bin[0];
- //ht_bin[1]=(int)head->addr;
- //ht_bin[0]=vaddr;
- }
- return head->addr;
- }
- head=head->next;
- }
- head=jump_dirty[vpage];
- while(head!=NULL) {
- if(head->vaddr==vaddr&&(head->reg32&flags)==0) {
- //printf("TRACE: count=%d next=%d (get_addr_32 match dirty %x: %x)\n",Count,next_interupt,vaddr,(int)head->addr);
- // Don't restore blocks which are about to expire from the cache
- if((((u_int)head->addr-(u_int)out)<<(32-TARGET_SIZE_2))>0x60000000+(MAX_OUTPUT_BLOCK_SIZE<<(32-TARGET_SIZE_2)))
- if(verify_dirty(head->addr)) {
- //printf("restore candidate: %x (%d) d=%d\n",vaddr,page,invalid_code[vaddr>>12]);
- invalid_code[vaddr>>12]=0;
- inv_code_start=inv_code_end=~0;
- memory_map[vaddr>>12]|=0x40000000;
- if(vpage<2048) {
-#ifndef DISABLE_TLB
- if(tlb_LUT_r[vaddr>>12]) {
- invalid_code[tlb_LUT_r[vaddr>>12]>>12]=0;
- memory_map[tlb_LUT_r[vaddr>>12]>>12]|=0x40000000;
- }
-#endif
- restore_candidate[vpage>>3]|=1<<(vpage&7);
- }
- else restore_candidate[page>>3]|=1<<(page&7);
- if(head->reg32==0) {
- int *ht_bin=hash_table[((vaddr>>16)^vaddr)&0xFFFF];
- if(ht_bin[0]==-1) {
- ht_bin[1]=(int)head->addr;
- ht_bin[0]=vaddr;
- }else if(ht_bin[2]==-1) {
- ht_bin[3]=(int)head->addr;
- ht_bin[2]=vaddr;
- }
- //ht_bin[3]=ht_bin[1];
- //ht_bin[2]=ht_bin[0];
- //ht_bin[1]=(int)head->addr;
- //ht_bin[0]=vaddr;
- }
- return head->addr;
- }
- }
- head=head->next;
- }
- //printf("TRACE: count=%d next=%d (get_addr_32 no-match %x,flags %x)\n",Count,next_interupt,vaddr,flags);
- int r=new_recompile_block(vaddr);
- if(r==0) return get_addr(vaddr);
- // Execute in unmapped page, generate pagefault execption
- Status|=2;
- Cause=(vaddr<<31)|0x8;
- EPC=(vaddr&1)?vaddr-5:vaddr;
- BadVAddr=(vaddr&~1);
- Context=(Context&0xFF80000F)|((BadVAddr>>9)&0x007FFFF0);
- EntryHi=BadVAddr&0xFFFFE000;
- return get_addr_ht(0x80000000);
-#endif
-}
-
void clear_all_regs(signed char regmap[])
{
int hr;
new_entry=malloc(sizeof(struct ll_entry));
assert(new_entry!=NULL);
new_entry->vaddr=vaddr;
- new_entry->reg32=0;
+ new_entry->reg_sv_flags=0;
new_entry->addr=addr;
new_entry->next=*head;
*head=new_entry;
}
-// Add virtual address mapping for 32-bit compiled block
-void ll_add_32(struct ll_entry **head,int vaddr,u_int reg32,void *addr)
+void ll_add_flags(struct ll_entry **head,int vaddr,u_int reg_sv_flags,void *addr)
{
ll_add(head,vaddr,addr);
-#ifndef FORCE32
- (*head)->reg32=reg32;
-#endif
+ (*head)->reg_sv_flags=reg_sv_flags;
}
// Check if an address is already compiled
struct ll_entry *head;
head=jump_in[page];
while(head!=NULL) {
- if(head->vaddr==vaddr&&head->reg32==0) {
+ if(head->vaddr==vaddr) {
if((((u_int)head->addr-(u_int)out)<<(32-TARGET_SIZE_2))>0x60000000+(MAX_OUTPUT_BLOCK_SIZE<<(32-TARGET_SIZE_2))) {
// Update existing entry with current address
if(ht_bin[0]==vaddr) {
inv_debug("INV: Restored %x (%x/%x)\n",head->vaddr, (int)head->addr, (int)clean_addr);
//printf("page=%x, addr=%x\n",page,head->vaddr);
//assert(head->vaddr>>12==(page|0x80000));
- ll_add_32(jump_in+ppage,head->vaddr,head->reg32,clean_addr);
+ ll_add_flags(jump_in+ppage,head->vaddr,head->reg_sv_flags,clean_addr);
int *ht_bin=hash_table[((head->vaddr>>16)^head->vaddr)&0xFFFF];
- if(!head->reg32) {
- if(ht_bin[0]==head->vaddr) {
- ht_bin[1]=(int)clean_addr; // Replace existing entry
- }
- if(ht_bin[2]==head->vaddr) {
- ht_bin[3]=(int)clean_addr; // Replace existing entry
- }
+ if(ht_bin[0]==head->vaddr) {
+ ht_bin[1]=(int)clean_addr; // Replace existing entry
+ }
+ if(ht_bin[2]==head->vaddr) {
+ ht_bin[3]=(int)clean_addr; // Replace existing entry
}
}
}
#endif
}
-int new_recompile_block(int addr)
+static u_int *get_source_start(u_int addr, u_int *limit)
{
-/*
- if(addr==0x800cd050) {
- int block;
- for(block=0x80000;block<0x80800;block++) invalidate_block(block);
- int n;
- for(n=0;n<=2048;n++) ll_clear(jump_dirty+n);
+ if (addr < 0x00200000 ||
+ (0xa0000000 <= addr && addr < 0xa0200000)) {
+ // used for BIOS calls mostly?
+ *limit = (addr&0xa0000000)|0x00200000;
+ return (u_int *)((u_int)rdram + (addr&0x1fffff));
+ }
+ else if (!Config.HLE && (
+ /* (0x9fc00000 <= addr && addr < 0x9fc80000) ||*/
+ (0xbfc00000 <= addr && addr < 0xbfc80000))) {
+ // BIOS
+ *limit = (addr & 0xfff00000) | 0x80000;
+ return (u_int *)((u_int)psxR + (addr&0x7ffff));
+ }
+ else if (addr >= 0x80000000 && addr < 0x80000000+RAM_SIZE) {
+ *limit = (addr & 0x80600000) + 0x00200000;
+ return (u_int *)((u_int)rdram + (addr&0x1fffff));
+ }
+}
+
+static u_int scan_for_ret(u_int addr)
+{
+ u_int limit = 0;
+ u_int *mem;
+
+ mem = get_source_start(addr, &limit);
+ if (mem == NULL)
+ return addr;
+
+ if (limit > addr + 0x1000)
+ limit = addr + 0x1000;
+ for (; addr < limit; addr += 4, mem++) {
+ if (*mem == 0x03e00008) // jr $ra
+ return addr + 8;
+ }
+}
+
+struct savestate_block {
+ uint32_t addr;
+ uint32_t regflags;
+};
+
+static int addr_cmp(const void *p1_, const void *p2_)
+{
+ const struct savestate_block *p1 = p1_, *p2 = p2_;
+ return p1->addr - p2->addr;
+}
+
+int new_dynarec_save_blocks(void *save, int size)
+{
+ struct savestate_block *blocks = save;
+ int maxcount = size / sizeof(blocks[0]);
+ struct savestate_block tmp_blocks[1024];
+ struct ll_entry *head;
+ int p, s, d, o, bcnt;
+ u_int addr;
+
+ o = 0;
+ for (p = 0; p < sizeof(jump_in) / sizeof(jump_in[0]); p++) {
+ bcnt = 0;
+ for (head = jump_in[p]; head != NULL; head = head->next) {
+ tmp_blocks[bcnt].addr = head->vaddr;
+ tmp_blocks[bcnt].regflags = head->reg_sv_flags;
+ bcnt++;
+ }
+ if (bcnt < 1)
+ continue;
+ qsort(tmp_blocks, bcnt, sizeof(tmp_blocks[0]), addr_cmp);
+
+ addr = tmp_blocks[0].addr;
+ for (s = d = 0; s < bcnt; s++) {
+ if (tmp_blocks[s].addr < addr)
+ continue;
+ if (d == 0 || tmp_blocks[d-1].addr != tmp_blocks[s].addr)
+ tmp_blocks[d++] = tmp_blocks[s];
+ addr = scan_for_ret(tmp_blocks[s].addr);
+ }
+
+ if (o + d > maxcount)
+ d = maxcount - o;
+ memcpy(&blocks[o], tmp_blocks, d * sizeof(blocks[0]));
+ o += d;
}
-*/
- //if(Count==365117028) tracedebug=1;
+
+ return o * sizeof(blocks[0]);
+}
+
+void new_dynarec_load_blocks(const void *save, int size)
+{
+ const struct savestate_block *blocks = save;
+ int count = size / sizeof(blocks[0]);
+ u_int regs_save[32];
+ uint32_t f;
+ int i, b;
+
+ get_addr(psxRegs.pc);
+
+ // change GPRs for speculation to at least partially work..
+ memcpy(regs_save, &psxRegs.GPR, sizeof(regs_save));
+ for (i = 1; i < 32; i++)
+ psxRegs.GPR.r[i] = 0x80000000;
+
+ for (b = 0; b < count; b++) {
+ for (f = blocks[b].regflags, i = 0; f; f >>= 1, i++) {
+ if (f & 1)
+ psxRegs.GPR.r[i] = 0x1f800000;
+ }
+
+ get_addr(blocks[b].addr);
+
+ for (f = blocks[b].regflags, i = 0; f; f >>= 1, i++) {
+ if (f & 1)
+ psxRegs.GPR.r[i] = 0x80000000;
+ }
+ }
+
+ memcpy(&psxRegs.GPR, regs_save, sizeof(regs_save));
+}
+
+int new_recompile_block(int addr)
+{
+ u_int pagelimit = 0;
+ u_int state_rflags = 0;
+ int i;
+
assem_debug("NOTCOMPILED: addr = %x -> %x\n", (int)addr, (int)out);
//printf("NOTCOMPILED: addr = %x -> %x\n", (int)addr, (int)out);
//printf("TRACE: count=%d next=%d (compile %x)\n",Count,next_interupt,addr);
rlist();
}*/
//rlist();
+
+ // this is just for speculation
+ for (i = 1; i < 32; i++) {
+ if ((psxRegs.GPR.r[i] & 0xffff0000) == 0x1f800000)
+ state_rflags |= 1 << i;
+ }
+
start = (u_int)addr&~3;
//assert(((u_int)addr&1)==0);
new_dynarec_did_compile=1;
-#ifdef PCSX
if (Config.HLE && start == 0x80001000) // hlecall
{
// XXX: is this enough? Maybe check hleSoftCall?
#ifdef __arm__
__clear_cache((void *)beginning,out);
#endif
- ll_add(jump_in+page,start,(void *)beginning);
+ ll_add_flags(jump_in+page,start,state_rflags,(void *)beginning);
return 0;
}
- else if ((u_int)addr < 0x00200000 ||
- (0xa0000000 <= addr && addr < 0xa0200000)) {
- // used for BIOS calls mostly?
- source = (u_int *)((u_int)rdram+(start&0x1fffff));
- pagelimit = (addr&0xa0000000)|0x00200000;
- }
- else if (!Config.HLE && (
-/* (0x9fc00000 <= addr && addr < 0x9fc80000) ||*/
- (0xbfc00000 <= addr && addr < 0xbfc80000))) {
- // BIOS
- source = (u_int *)((u_int)psxR+(start&0x7ffff));
- pagelimit = (addr&0xfff00000)|0x80000;
- }
- else
-#endif
-#ifdef MUPEN64
- if ((int)addr >= 0xa4000000 && (int)addr < 0xa4001000) {
- source = (u_int *)((u_int)SP_DMEM+start-0xa4000000);
- pagelimit = 0xa4001000;
- }
- else
-#endif
- if ((int)addr >= 0x80000000 && (int)addr < 0x80000000+RAM_SIZE) {
- source = (u_int *)((u_int)rdram+start-0x80000000);
- pagelimit = 0x80000000+RAM_SIZE;
- }
-#ifndef DISABLE_TLB
- else if ((signed int)addr >= (signed int)0xC0000000) {
- //printf("addr=%x mm=%x\n",(u_int)addr,(memory_map[start>>12]<<2));
- //if(tlb_LUT_r[start>>12])
- //source = (u_int *)(((int)rdram)+(tlb_LUT_r[start>>12]&0xFFFFF000)+(((int)addr)&0xFFF)-0x80000000);
- if((signed int)memory_map[start>>12]>=0) {
- source = (u_int *)((u_int)(start+(memory_map[start>>12]<<2)));
- pagelimit=(start+4096)&0xFFFFF000;
- int map=memory_map[start>>12];
- int i;
- for(i=0;i<5;i++) {
- //printf("start: %x next: %x\n",map,memory_map[pagelimit>>12]);
- if((map&0xBFFFFFFF)==(memory_map[pagelimit>>12]&0xBFFFFFFF)) pagelimit+=4096;
- }
- assem_debug("pagelimit=%x\n",pagelimit);
- assem_debug("mapping=%x (%x)\n",memory_map[start>>12],(memory_map[start>>12]<<2)+start);
- }
- else {
- assem_debug("Compile at unmapped memory address: %x \n", (int)addr);
- //assem_debug("start: %x next: %x\n",memory_map[start>>12],memory_map[(start+4096)>>12]);
- return -1; // Caller will invoke exception handler
- }
- //printf("source= %x\n",(int)source);
- }
-#endif
- else {
- SysPrintf("Compile at bogus memory address: %x \n", (int)addr);
+
+ source = get_source_start(start, &pagelimit);
+ if (source == NULL) {
+ SysPrintf("Compile at bogus memory address: %08x\n", addr);
exit(1);
}
/* Pass 9: linker */
/* Pass 10: garbage collection / free memory */
- int i,j;
+ int j;
int done=0;
unsigned int type,op,op2;
{
cc+=2; // 2 cycle penalty (after CLOCK_DIVIDER)
}
+ else if(i>1&&itype[i]==STORE&&itype[i-1]==STORE&&itype[i-2]==STORE&&!bt[i])
+ {
+ cc+=4;
+ }
else if(itype[i]==C2LS)
{
cc+=4;
u_int page=get_page(vaddr);
u_int vpage=get_vpage(vaddr);
literal_pool(256);
- //if(!(is32[i]&(~unneeded_reg_upper[i])&~(1LL<<CCREG)))
-#ifndef FORCE32
- if(!requires_32bit[i])
-#else
- if(1)
-#endif
{
assem_debug("%8x (%d) <- %8x\n",instr_addr[i],i,start+i*4);
assem_debug("jump_in: %x\n",start+i*4);
ll_add(jump_dirty+vpage,vaddr,(void *)out);
int entry_point=do_dirty_stub(i);
- ll_add(jump_in+page,vaddr,(void *)entry_point);
+ ll_add_flags(jump_in+page,vaddr,state_rflags,(void *)entry_point);
// If there was an existing entry in the hash table,
// replace it with the new address.
// Don't add new entries. We'll insert the
ht_bin[3]=entry_point;
}
}
- else
- {
- u_int r=requires_32bit[i]|!!(requires_32bit[i]>>32);
- assem_debug("%8x (%d) <- %8x\n",instr_addr[i],i,start+i*4);
- assem_debug("jump_in: %x (restricted - %x)\n",start+i*4,r);
- //int entry_point=(int)out;
- ////assem_debug("entry_point: %x\n",entry_point);
- //load_regs_entry(i);
- //if(entry_point==(int)out)
- // entry_point=instr_addr[i];
- //else
- // emit_jmp(instr_addr[i]);
- //ll_add_32(jump_in+page,vaddr,r,(void *)entry_point);
- ll_add_32(jump_dirty+vpage,vaddr,r,(void *)out);
- int entry_point=do_dirty_stub(i);
- ll_add_32(jump_in+page,vaddr,r,(void *)entry_point);
- }
}
}
}
void new_dynarec_cleanup();
void new_dynarec_clear_full();
void new_dyna_start();
+int new_dynarec_save_blocks(void *save, int size);
+void new_dynarec_load_blocks(const void *save, int size);
void invalidate_all_pages();
void invalidate_block(unsigned int block);
extern u32 event_cycles[PSXINT_COUNT];
extern u32 next_interupt;
-void new_dyna_save(void);
+void new_dyna_before_save(void);
void new_dyna_after_save(void);
-void new_dyna_restore(void);
+void new_dyna_freeze(void *f, int mode);
#define new_dyna_set_event(e, c) { \
s32 c_ = c; \
Compiling
---------
-'./configure && make' should work for the most part.
+For libretro build, just doing "make -f Makefile.libretro" is recommended as
+it's the way libretro team is building the core and only Makefile.libretro is
+maintained by them.
+
+For standalone build, './configure && make' should work for the most part.
When compiling for ARM, it's advisable to tell configure script the CPU, FPU
and ABI that matches your target system to get best performance, like this:
Changelog
---------
+r20 (2014-12-25)
+* fixed various sound accuracy issues, like effects in ff7-ff9
+ for standalone build, audio will no longer slow down when emu is not fast
+ enough and stutter instead, as the former behavior causes accuracy issues.
+ Old mode can be restored in SPU plugin config options, but is not recommended.
+* savestates now save small parts of dynarec state to reduce dynarec related
+ slowdowns after savestate load
+* menu: fixed file browser issues with filesystems like exfat-fuse
+* menu: memcard manager: selected card is saved in config now
+* standalone: added some basic scanline efect
+* some CD image loading fixes
+* converted asm code to be compatible with more assemblers, like Apple's gas
++ libretro: added Makefile.libretro and support for various platforms like
+ iOS and QNX. Makefile.libretro is recommended way to do libretro builds
+ (patches from CatalystG, squarepusher, notaz and others, see git).
+* some other minor fixes
+
r19 (2013-03-17)
+ libretro: added region, multidisk support
* more work on cdrom code