diff --git a/Gamecube/GamecubeMain.cpp b/Gamecube/GamecubeMain.cpp index 246e9941..7c3b4d6f 100644 --- a/Gamecube/GamecubeMain.cpp +++ b/Gamecube/GamecubeMain.cpp @@ -128,6 +128,8 @@ int in_type[8] = { PSE_PAD_TYPE_NONE, PSE_PAD_TYPE_NONE }; +unsigned short in_keystate[8]; + extern "C" int stop; static struct { diff --git a/Gamecube/GamecubePlugins.c b/Gamecube/GamecubePlugins.c index ae5c7126..467c2195 100644 --- a/Gamecube/GamecubePlugins.c +++ b/Gamecube/GamecubePlugins.c @@ -82,6 +82,9 @@ void CALLBACK SPUwriteRegister(unsigned long reg, unsigned short val, unsigned i long CALLBACK SPUopen(void); long CALLBACK SPUclose(void); long CALLBACK SPUfreeze(uint32_t ulFreezeMode, void * pF, uint32_t cycles); +void CALLBACK SPUsetCDvol(unsigned char ll, unsigned char lr, + unsigned char rl, unsigned char rr, unsigned int cycle); + #define EMPTY_PLUGIN \ { NULL, \ @@ -150,6 +153,8 @@ long CALLBACK SPUfreeze(uint32_t ulFreezeMode, void * pF, uint32_t cycles); (void*)SPUplayADPCMchannel}, \ { "SPUfreeze", \ (void*)SPUfreeze}, \ + { "SPUsetCDvol", \ + (void*)SPUsetCDvol}, \ { "SPUregisterCallback", \ (void*)SPUregisterCallback}, \ { "SPUregisterCDDAVolume", \ diff --git a/pcsx_rearmed/.gitrepo b/pcsx_rearmed/.gitrepo index 890d182a..c8a7824a 100644 --- a/pcsx_rearmed/.gitrepo +++ b/pcsx_rearmed/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/libretro/pcsx_rearmed.git branch = master - commit = c396a646b9ce3082bc6aee7da35219f6424c99b6 - parent = 879acaff3bcdd4189e49b9f0bf56dd7539471ebc + commit = 5ee1c9269d333936eba3e7e3259956f601ff5edd + parent = 942faf909f84e40c01883547ee430416baf5c2f0 method = merge cmdver = 0.4.6 diff --git a/pcsx_rearmed/Makefile b/pcsx_rearmed/Makefile index be943918..4786a922 100644 --- a/pcsx_rearmed/Makefile +++ b/pcsx_rearmed/Makefile @@ -12,6 +12,9 @@ else CFLAGS += -O2 -DNDEBUG endif endif +ifeq ($(DEBUG_ASAN), 1) +CFLAGS += -fsanitize=address +endif CFLAGS += -DP_HAVE_MMAP=$(if $(NO_MMAP),0,1) \ -DP_HAVE_PTHREAD=$(if $(NO_PTHREAD),0,1) \ -DP_HAVE_POSIX_MEMALIGN=$(if $(NO_POSIX_MEMALIGN),0,1) \ @@ -45,6 +48,9 @@ endif CC_LINK ?= $(CC) CC_AS ?= $(CC) LDFLAGS += $(MAIN_LDFLAGS) +ifeq ($(DEBUG_ASAN), 1) +LDFLAGS += -static-libasan +endif EXTRA_LDFLAGS ?= -Wl,-Map=$@.map LDLIBS += $(MAIN_LDLIBS) ifdef PCNT @@ -173,7 +179,7 @@ ifeq "$(ARCH)" "arm" OBJS += plugins/dfsound/arm_utils.o endif ifeq "$(HAVE_C64_TOOLS)" "1" -plugins/dfsound/spu.o: CFLAGS += -DC64X_DSP +plugins/dfsound/%.o: CFLAGS += -DC64X_DSP -DWANT_THREAD_CODE plugins/dfsound/spu.o: plugins/dfsound/spu_c64x.c frontend/menu.o: CFLAGS += -DC64X_DSP endif @@ -307,6 +313,8 @@ 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 +CFLAGS += -gdwarf-3 -ffunction-sections -fdata-sections +LDFLAGS += -Wl,--gc-sections endif ifeq "$(PLATFORM)" "caanoo" OBJS += frontend/libpicofe/gp2x/in_gp2x.o frontend/warm/warm.o diff --git a/pcsx_rearmed/Makefile.libretro b/pcsx_rearmed/Makefile.libretro index 9fe5365a..1169d892 100644 --- a/pcsx_rearmed/Makefile.libretro +++ b/pcsx_rearmed/Makefile.libretro @@ -111,7 +111,7 @@ ifneq (,$(shell $(CC) -E -dD $(CFLAGS) include/arm_features.h | grep 'HAVE_NEON3 BUILTIN_GPU = neon endif endif -ifneq (,$(findstring $(ARCH_DETECTED),i686 x86_64 arm64 aarch64)) +ifneq (,$(filter $(ARCH_DETECTED),i686 x86_64 arm64 aarch64)) BUILTIN_GPU = neon endif diff --git a/pcsx_rearmed/deps/lightning/.gitrepo b/pcsx_rearmed/deps/lightning/.gitrepo index 6e32aaa6..55cc9e6b 100644 --- a/pcsx_rearmed/deps/lightning/.gitrepo +++ b/pcsx_rearmed/deps/lightning/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/pcercuei/gnu_lightning.git branch = pcsx_rearmed - commit = 4d1ef4c372a2d7cd1cd25c637a18d802af7dfcb4 - parent = 0f67f144fb172e9eaa7a722a0a853350f77aad15 + commit = de026794c71386983034461bce2df3c63ccd5827 + parent = fb67ea334b0f3984a114a6e306806a56347a83ba method = merge cmdver = 0.4.6 diff --git a/pcsx_rearmed/deps/lightning/include/lightning.h.in b/pcsx_rearmed/deps/lightning/include/lightning.h.in index 6d512352..4ab4a0a9 100644 --- a/pcsx_rearmed/deps/lightning/include/lightning.h.in +++ b/pcsx_rearmed/deps/lightning/include/lightning.h.in @@ -23,6 +23,7 @@ #include #include @MAYBE_INCLUDE_STDINT_H@ +#include #include #include @@ -1220,6 +1221,7 @@ typedef void (*jit_free_func_ptr) (void*); /* * Prototypes */ +extern void init_jit_with_debug(const char*,FILE*); extern void init_jit(const char*); extern void finish_jit(void); diff --git a/pcsx_rearmed/deps/lightning/include/lightning/jit_private.h b/pcsx_rearmed/deps/lightning/include/lightning/jit_private.h index 9f8caf65..a730d73e 100644 --- a/pcsx_rearmed/deps/lightning/include/lightning/jit_private.h +++ b/pcsx_rearmed/deps/lightning/include/lightning/jit_private.h @@ -873,8 +873,8 @@ _emit_ldxi_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t); extern void _emit_stxi_d(jit_state_t*, jit_word_t, jit_int32_t, jit_int32_t); -extern void jit_init_print(void); -extern void jit_init_debug(const char*); +extern void jit_init_print(FILE*); +extern void jit_init_debug(const char*, FILE*); extern void jit_finish_debug(void); extern void jit_init_note(void); diff --git a/pcsx_rearmed/deps/lightning/lib/jit_disasm.c b/pcsx_rearmed/deps/lightning/lib/jit_disasm.c index a6981fa5..90d90b0f 100644 --- a/pcsx_rearmed/deps/lightning/lib/jit_disasm.c +++ b/pcsx_rearmed/deps/lightning/lib/jit_disasm.c @@ -71,9 +71,9 @@ static int fprintf_styled(void * stream, enum disassembler_style style, const ch * Implementation */ void -jit_init_debug(const char *progname) +jit_init_debug(const char *progname, FILE *stream) { - jit_init_print(); + jit_init_print(stream); #if DISASSEMBLER bfd_init(); @@ -89,7 +89,7 @@ jit_init_debug(const char *progname) bfd_check_format(disasm_bfd, bfd_object); bfd_check_format(disasm_bfd, bfd_archive); if (!disasm_stream) - disasm_stream = stdout; + disasm_stream = stream; #if BINUTILS_2_38 INIT_DISASSEMBLE_INFO(disasm_info, disasm_stream, fprintf, fprintf_styled); diff --git a/pcsx_rearmed/deps/lightning/lib/jit_print.c b/pcsx_rearmed/deps/lightning/lib/jit_print.c index 2244aab0..079112ba 100644 --- a/pcsx_rearmed/deps/lightning/lib/jit_print.c +++ b/pcsx_rearmed/deps/lightning/lib/jit_print.c @@ -75,10 +75,10 @@ static FILE *print_stream; * Implementation */ void -jit_init_print(void) +jit_init_print(FILE *stream) { if (!print_stream) - print_stream = stdout; + print_stream = stream; } void diff --git a/pcsx_rearmed/deps/lightning/lib/lightning.c b/pcsx_rearmed/deps/lightning/lib/lightning.c index 39c4fc2e..646d9db5 100644 --- a/pcsx_rearmed/deps/lightning/lib/lightning.c +++ b/pcsx_rearmed/deps/lightning/lib/lightning.c @@ -181,13 +181,19 @@ _patch_register(jit_state_t *jit, jit_node_t *node, jit_node_t *link, * Implementation */ void -init_jit(const char *progname) +init_jit_with_debug(const char *progname, FILE *dbg_out) { jit_get_cpu(); - jit_init_debug(progname); + jit_init_debug(progname, dbg_out); jit_init_size(); } +void +init_jit(const char *progname) +{ + init_jit_with_debug(progname, stderr); +} + void finish_jit(void) { diff --git a/pcsx_rearmed/deps/lightrec/.gitrepo b/pcsx_rearmed/deps/lightrec/.gitrepo index 96c4feea..1f5764a3 100644 --- a/pcsx_rearmed/deps/lightrec/.gitrepo +++ b/pcsx_rearmed/deps/lightrec/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/pcercuei/lightrec.git branch = master - commit = b9e4089b3b6121f2077dc85a8fe7f934e3ae1c20 - parent = bbe0dac4b7062d5ead765329d9ddb1e1fe01eee2 + commit = d88760e40c1d2a5698c7b6f6a53cce31fda799f0 + parent = 963f41620dce6ddb2527b7e3dced09564031f783 method = merge cmdver = 0.4.6 diff --git a/pcsx_rearmed/deps/lightrec/CMakeLists.txt b/pcsx_rearmed/deps/lightrec/CMakeLists.txt index dfe35a02..9ca058ec 100644 --- a/pcsx_rearmed/deps/lightrec/CMakeLists.txt +++ b/pcsx_rearmed/deps/lightrec/CMakeLists.txt @@ -54,7 +54,7 @@ list(APPEND LIGHTREC_HEADERS option(ENABLE_FIRST_PASS "Run the interpreter as first-pass optimization" ON) -option(ENABLE_THREADED_COMPILER "Enable threaded compiler" OFF) +option(ENABLE_THREADED_COMPILER "Enable threaded compiler" ON) if (ENABLE_THREADED_COMPILER) list(APPEND LIGHTREC_SOURCES recompiler.c reaper.c) diff --git a/pcsx_rearmed/deps/lightrec/emitter.c b/pcsx_rearmed/deps/lightrec/emitter.c index b8025aac..3875e58e 100644 --- a/pcsx_rearmed/deps/lightrec/emitter.c +++ b/pcsx_rearmed/deps/lightrec/emitter.c @@ -107,7 +107,7 @@ static void lightrec_emit_end_of_block(struct lightrec_cstate *state, } if (has_ds && op_flag_load_delay(ds->flags) - && opcode_is_load(ds->c) && !state->no_load_delay) { + && opcode_has_load_delay(ds->c) && !state->no_load_delay) { /* If the delay slot is a load opcode, its target register * will be written after the first opcode of the target is * executed. Handle this by jumping to a special section of diff --git a/pcsx_rearmed/deps/lightrec/interpreter.c b/pcsx_rearmed/deps/lightrec/interpreter.c index 9078b693..4267bec2 100644 --- a/pcsx_rearmed/deps/lightrec/interpreter.c +++ b/pcsx_rearmed/deps/lightrec/interpreter.c @@ -31,6 +31,7 @@ struct interpreter { struct opcode *op; u32 cycles; bool delay_slot; + bool load_delay; u16 offset; }; @@ -150,14 +151,13 @@ static u32 int_delay_slot(struct interpreter *inter, u32 pc, bool branch) .state = state, .cycles = inter->cycles, .delay_slot = true, - .block = NULL, + .load_delay = true, }; bool run_first_op = false, dummy_ld = false, save_rs = false, load_in_ds, branch_in_ds = false, branch_at_addr = false, branch_taken; u32 new_rt, old_rs = 0, new_rs = 0; - u32 next_pc, ds_next_pc; - u32 cause, epc; + u32 next_pc, ds_next_pc, epc; if (op->i.op == OP_CP0 && op->r.rs == OP_CP0_RFE) { /* When an IRQ happens, the PSX exception handlers (when done) @@ -168,11 +168,13 @@ static u32 int_delay_slot(struct interpreter *inter, u32 pc, bool branch) * but on branch boundaries, we need to adjust the return * address so that the GTE opcode is effectively executed. */ - cause = state->regs.cp0[13]; epc = state->regs.cp0[14]; - if (!(cause & 0x7c) && epc == pc - 4) - pc -= 4; + if (epc == pc - 4) { + op_next = lightrec_read_opcode(state, epc); + if (op_next.i.op == OP_CP2) + pc -= 4; + } } if (inter->delay_slot) { @@ -187,7 +189,7 @@ static u32 int_delay_slot(struct interpreter *inter, u32 pc, bool branch) * interpreter in that case. * Same goes for when we have a branch in a delay slot of another * branch. */ - load_in_ds = opcode_is_load(op->c) || opcode_is_mfc(op->c); + load_in_ds = opcode_has_load_delay(op->c); branch_in_ds = has_delay_slot(op->c); if (branch) { @@ -600,7 +602,7 @@ static u32 int_io(struct interpreter *inter, bool is_load) u32 *reg_cache = inter->state->regs.gpr; u32 val, *flags = NULL; - if (inter->block) + if (!inter->load_delay && inter->block) flags = &inter->op->flags; val = lightrec_rw(inter->state, inter->op->c, @@ -1188,16 +1190,14 @@ static u32 int_META(struct interpreter *inter) static u32 lightrec_emulate_block_list(struct lightrec_state *state, struct block *block, u32 offset) { - struct interpreter inter; + struct interpreter inter = { + .block = block, + .state = state, + .offset = offset, + .op = &block->opcode_list[offset], + }; u32 pc; - inter.block = block; - inter.state = state; - inter.offset = offset; - inter.op = &block->opcode_list[offset]; - inter.cycles = 0; - inter.delay_slot = false; - pc = lightrec_int_op(&inter); /* Add the cycles of the last branch */ @@ -1253,9 +1253,8 @@ u32 lightrec_handle_load_delay(struct lightrec_state *state, struct interpreter inter = { .block = block, .state = state, - .offset = 0, .op = op, - .cycles = 0, + .load_delay = true, }; bool branch_taken; u32 reg_mask, next_pc; diff --git a/pcsx_rearmed/deps/lightrec/lightrec.c b/pcsx_rearmed/deps/lightrec/lightrec.c index f589ce85..1cfc4274 100644 --- a/pcsx_rearmed/deps/lightrec/lightrec.c +++ b/pcsx_rearmed/deps/lightrec/lightrec.c @@ -35,6 +35,8 @@ static bool lightrec_block_is_fully_tagged(const struct block *block); static void lightrec_mtc2(struct lightrec_state *state, u8 reg, u32 data); static u32 lightrec_mfc2(struct lightrec_state *state, u8 reg); +static void lightrec_reap_block(struct lightrec_state *state, void *data); + static void lightrec_default_sb(struct lightrec_state *state, u32 opcode, void *host, u32 addr, u32 data) { @@ -703,9 +705,15 @@ static struct block * lightrec_get_block(struct lightrec_state *state, u32 pc) if (ENABLE_THREADED_COMPILER) lightrec_recompiler_remove(state->rec, block); - lightrec_unregister_block(state->block_cache, block); remove_from_code_lut(state->block_cache, block); - lightrec_free_block(state, block); + + if (ENABLE_THREADED_COMPILER) { + lightrec_reaper_add(state->reaper, + lightrec_reap_block, block); + } else { + lightrec_unregister_block(state->block_cache, block); + lightrec_free_block(state, block); + } } block = NULL; @@ -1559,6 +1567,8 @@ static void lightrec_reap_opcode_list(struct lightrec_state *state, void *data) int lightrec_compile_block(struct lightrec_cstate *cstate, struct block *block) { + struct block *dead_blocks[ARRAY_SIZE(cstate->targets)]; + u32 was_dead[ARRAY_SIZE(cstate->targets) / 8]; struct lightrec_state *state = cstate->state; struct lightrec_branch_target *target; bool fully_tagged = false; @@ -1677,11 +1687,8 @@ int lightrec_compile_block(struct lightrec_cstate *cstate, /* Add compiled function to the LUT */ lut_write(state, lut_offset(block->pc), block->function); - if (ENABLE_THREADED_COMPILER) - lightrec_reaper_continue(state->reaper); - /* Detect old blocks that have been covered by the new one */ - for (i = 0; i < cstate->nb_targets; i++) { + for (i = 0; ENABLE_THREADED_COMPILER && i < cstate->nb_targets; i++) { target = &cstate->targets[i]; if (!target->offset) @@ -1689,12 +1696,6 @@ int lightrec_compile_block(struct lightrec_cstate *cstate, offset = block->pc + target->offset * sizeof(u32); - /* Pause the reaper while we search for the block until we set - * the BLOCK_IS_DEAD flag, otherwise the block may be removed - * under our feet. */ - if (ENABLE_THREADED_COMPILER) - lightrec_reaper_pause(state->reaper); - block2 = lightrec_find_block(state->block_cache, offset); if (block2) { /* No need to check if block2 is compilable - it must @@ -1703,17 +1704,26 @@ int lightrec_compile_block(struct lightrec_cstate *cstate, /* Set the "block dead" flag to prevent the dynarec from * recompiling this block */ old_flags = block_set_flags(block2, BLOCK_IS_DEAD); + + if (old_flags & BLOCK_IS_DEAD) + was_dead[i / 32] |= BIT(i % 32); + else + was_dead[i / 32] &= ~BIT(i % 32); } - if (ENABLE_THREADED_COMPILER) { - lightrec_reaper_continue(state->reaper); + dead_blocks[i] = block2; - /* If block2 was pending for compilation, cancel it. - * If it's being compiled right now, wait until it - * finishes. */ - if (block2) - lightrec_recompiler_remove(state->rec, block2); - } + /* If block2 was pending for compilation, cancel it. + * If it's being compiled right now, wait until it finishes. */ + if (block2) + lightrec_recompiler_remove(state->rec, block2); + } + + for (i = 0; i < cstate->nb_targets; i++) { + target = &cstate->targets[i]; + + if (!target->offset) + continue; /* We know from now on that block2 (if present) isn't going to * be compiled. We can override the LUT entry with our new @@ -1721,6 +1731,12 @@ int lightrec_compile_block(struct lightrec_cstate *cstate, offset = lut_offset(block->pc) + target->offset; lut_write(state, offset, jit_address(target->label)); + if (ENABLE_THREADED_COMPILER) { + block2 = dead_blocks[i]; + } else { + offset = block->pc + target->offset * sizeof(u32); + block2 = lightrec_find_block(state->block_cache, offset); + } if (block2) { pr_debug("Reap block 0x%08x as it's covered by block " "0x%08x\n", block2->pc, block->pc); @@ -1729,7 +1745,7 @@ int lightrec_compile_block(struct lightrec_cstate *cstate, if (!ENABLE_THREADED_COMPILER) { lightrec_unregister_block(state->block_cache, block2); lightrec_free_block(state, block2); - } else if (!(old_flags & BLOCK_IS_DEAD)) { + } else if (!(was_dead[i / 32] & BIT(i % 32))) { lightrec_reaper_add(state->reaper, lightrec_reap_block, block2); @@ -1737,6 +1753,9 @@ int lightrec_compile_block(struct lightrec_cstate *cstate, } } + if (ENABLE_THREADED_COMPILER) + lightrec_reaper_continue(state->reaper); + if (ENABLE_DISASSEMBLER) { pr_debug("Compiling block at PC: 0x%08x\n", block->pc); jit_disassemble(); @@ -1941,7 +1960,7 @@ struct lightrec_state * lightrec_init(char *argv0, else lut_size = CODE_LUT_SIZE * sizeof(void *); - init_jit(argv0); + init_jit_with_debug(argv0, stdout); state = calloc(1, sizeof(*state) + lut_size); if (!state) diff --git a/pcsx_rearmed/deps/lightrec/optimizer.c b/pcsx_rearmed/deps/lightrec/optimizer.c index 90b21398..199ca40b 100644 --- a/pcsx_rearmed/deps/lightrec/optimizer.c +++ b/pcsx_rearmed/deps/lightrec/optimizer.c @@ -299,6 +299,9 @@ static bool reg_is_dead(const struct opcode *list, unsigned int offset, u8 reg) if (opcode_writes_register(list[i].c, reg)) return true; + if (is_syscall(list[i].c)) + return false; + if (has_delay_slot(list[i].c)) { if (op_flag_no_ds(list[i].flags) || opcode_reads_register(list[i + 1].c, reg)) @@ -342,7 +345,7 @@ static bool reg_is_read_or_written(const struct opcode *list, return reg_is_read(list, a, b, reg) || reg_is_written(list, a, b, reg); } -bool opcode_is_mfc(union code op) +static bool opcode_is_mfc(union code op) { switch (op.i.op) { case OP_CP0: @@ -374,7 +377,7 @@ bool opcode_is_mfc(union code op) return false; } -bool opcode_is_load(union code op) +static bool opcode_is_load(union code op) { switch (op.i.op) { case OP_LB: @@ -408,6 +411,12 @@ static bool opcode_is_store(union code op) } } +bool opcode_has_load_delay(union code op) +{ + return (opcode_is_load(op) && op.i.rt && op.i.op != OP_LWC2) + || opcode_is_mfc(op); +} + static u8 opcode_get_io_size(union code op) { switch (op.i.op) { @@ -1382,7 +1391,7 @@ static int lightrec_handle_load_delays(struct lightrec_state *state, for (i = 0; i < block->nb_ops; i++) { op = &list[i]; - if (!opcode_is_load(op->c) || !op->c.i.rt || op->c.i.op == OP_LWC2) + if (!opcode_has_load_delay(op->c)) continue; if (!is_delay_slot(list, i)) { diff --git a/pcsx_rearmed/deps/lightrec/optimizer.h b/pcsx_rearmed/deps/lightrec/optimizer.h index f2b1f30f..26666520 100644 --- a/pcsx_rearmed/deps/lightrec/optimizer.h +++ b/pcsx_rearmed/deps/lightrec/optimizer.h @@ -16,8 +16,7 @@ __cnst _Bool opcode_writes_register(union code op, u8 reg); __cnst u64 opcode_write_mask(union code op); __cnst _Bool has_delay_slot(union code op); _Bool is_delay_slot(const struct opcode *list, unsigned int offset); -__cnst _Bool opcode_is_mfc(union code op); -__cnst _Bool opcode_is_load(union code op); +__cnst _Bool opcode_has_load_delay(union code op); __cnst _Bool opcode_is_io(union code op); __cnst _Bool is_unconditional_jump(union code c); __cnst _Bool is_syscall(union code c); diff --git a/pcsx_rearmed/deps/lightrec/recompiler.c b/pcsx_rearmed/deps/lightrec/recompiler.c index c764f119..a6d2f322 100644 --- a/pcsx_rearmed/deps/lightrec/recompiler.c +++ b/pcsx_rearmed/deps/lightrec/recompiler.c @@ -23,6 +23,7 @@ struct block_rec { struct block *block; struct slist_elm slist; + unsigned int requests; bool compiling; }; @@ -64,19 +65,20 @@ static unsigned int get_processors_count(void) return nb < 1 ? 1 : nb; } -static struct slist_elm * lightrec_get_first_elm(struct slist_elm *head) +static struct block_rec * lightrec_get_best_elm(struct slist_elm *head) { - struct block_rec *block_rec; + struct block_rec *block_rec, *best = NULL; struct slist_elm *elm; for (elm = slist_first(head); elm; elm = elm->next) { block_rec = container_of(elm, struct block_rec, slist); - if (!block_rec->compiling) - return elm; + if (!block_rec->compiling + && (!best || block_rec->requests > best->requests)) + best = block_rec; } - return NULL; + return best; } static bool lightrec_cancel_block_rec(struct recompiler *rec, @@ -126,12 +128,10 @@ static void lightrec_compile_list(struct recompiler *rec, struct recompiler_thd *thd) { struct block_rec *block_rec; - struct slist_elm *next; struct block *block; int ret; - while (!!(next = lightrec_get_first_elm(&rec->slist))) { - block_rec = container_of(next, struct block_rec, slist); + while (!!(block_rec = lightrec_get_best_elm(&rec->slist))) { block_rec->compiling = true; block = block_rec->block; @@ -166,7 +166,7 @@ static void lightrec_compile_list(struct recompiler *rec, pthread_mutex_lock(&rec->mutex); - slist_remove(&rec->slist, next); + slist_remove(&rec->slist, &block_rec->slist); lightrec_free(rec->state, MEM_FOR_LIGHTREC, sizeof(*block_rec), block_rec); pthread_cond_broadcast(&rec->cond2); @@ -314,8 +314,9 @@ void lightrec_free_recompiler(struct recompiler *rec) int lightrec_recompiler_add(struct recompiler *rec, struct block *block) { - struct slist_elm *elm, *prev; + struct slist_elm *elm; struct block_rec *block_rec; + u32 pc1, pc2; int ret = 0; pthread_mutex_lock(&rec->mutex); @@ -331,20 +332,23 @@ int lightrec_recompiler_add(struct recompiler *rec, struct block *block) if (block_has_flag(block, BLOCK_IS_DEAD)) goto out_unlock; - for (elm = slist_first(&rec->slist), prev = NULL; elm; - prev = elm, elm = elm->next) { + for (elm = slist_first(&rec->slist); elm; elm = elm->next) { block_rec = container_of(elm, struct block_rec, slist); if (block_rec->block == block) { - /* The block to compile is already in the queue - bump - * it to the top of the list, unless the block is being - * recompiled. */ - if (prev && !block_rec->compiling && - !block_has_flag(block, BLOCK_SHOULD_RECOMPILE)) { - slist_remove_next(prev); - slist_append(&rec->slist, elm); - } + /* The block to compile is already in the queue - + * increment its counter to increase its priority */ + block_rec->requests++; + goto out_unlock; + } + pc1 = kunseg(block_rec->block->pc); + pc2 = kunseg(block->pc); + if (pc2 >= pc1 && pc2 < pc1 + block_rec->block->nb_ops * 4) { + /* The block we want to compile is already covered by + * another one in the queue - increment its counter to + * increase its priority */ + block_rec->requests++; goto out_unlock; } } @@ -365,14 +369,11 @@ int lightrec_recompiler_add(struct recompiler *rec, struct block *block) block_rec->block = block; block_rec->compiling = false; + block_rec->requests = 1; elm = &rec->slist; - /* If the block is being recompiled, push it to the end of the queue; - * otherwise push it to the front of the queue. */ - if (block_has_flag(block, BLOCK_SHOULD_RECOMPILE)) - for (; elm->next; elm = elm->next); - + /* Push the new entry to the front of the queue */ slist_append(elm, &block_rec->slist); /* Signal the thread */ diff --git a/pcsx_rearmed/frontend/libpicofe b/pcsx_rearmed/frontend/libpicofe index 740c6f25..be3677f1 160000 --- a/pcsx_rearmed/frontend/libpicofe +++ b/pcsx_rearmed/frontend/libpicofe @@ -1 +1 @@ -Subproject commit 740c6f25f8240deeb732a0a999f2a57cc2f6f6d6 +Subproject commit be3677f1867cef839334e7746ea1c8205ec73c8c diff --git a/pcsx_rearmed/frontend/libretro.c b/pcsx_rearmed/frontend/libretro.c index c47d260b..7b29a23a 100644 --- a/pcsx_rearmed/frontend/libretro.c +++ b/pcsx_rearmed/frontend/libretro.c @@ -76,6 +76,13 @@ static retro_set_rumble_state_t rumble_cb; static struct retro_log_callback logging; static retro_log_printf_t log_cb; +#define LogWarn(fmt, ...) do { \ + if (log_cb) log_cb(RETRO_LOG_WARN, fmt, ##__VA_ARGS__); \ +} while (0) +#define LogErr(fmt, ...) do { \ + if (log_cb) log_cb(RETRO_LOG_ERROR, fmt, ##__VA_ARGS__); \ +} while (0) + static unsigned msg_interface_version = 0; static void *vout_buf; @@ -84,7 +91,6 @@ static int vout_width = 256, vout_height = 240, vout_pitch = 256; static int vout_fb_dirty; static int psx_w, psx_h; static bool vout_can_dupe; -static bool duping_enable; static bool found_bios; static bool display_internal_fps = false; static unsigned frame_count = 0; @@ -145,7 +151,9 @@ int in_mouse[8][2]; int multitap1 = 0; int multitap2 = 0; int in_enable_vibration = 1; -int in_enable_crosshair[2] = { 0, 0 }; +static int in_enable_crosshair[2] = { 0, 0 }; +static int in_dualshock_analog_combo = 0; +static bool in_dualshock_toggling = false; // NegCon adjustment parameters // > The NegCon 'twist' action is somewhat awkward when mapped @@ -235,10 +243,13 @@ static void set_vout_fb() fb.access_flags = RETRO_MEMORY_ACCESS_WRITE; vout_pitch = vout_width; - if (environ_cb(RETRO_ENVIRONMENT_GET_CURRENT_SOFTWARE_FRAMEBUFFER, &fb) && fb.format == RETRO_PIXEL_FORMAT_RGB565) { + if (environ_cb(RETRO_ENVIRONMENT_GET_CURRENT_SOFTWARE_FRAMEBUFFER, &fb) + && fb.format == RETRO_PIXEL_FORMAT_RGB565 + && vout_can_dupe) + { vout_buf_ptr = fb.data; if (fb.pitch / 2 != vout_pitch && fb.pitch != vout_width * 2) - SysPrintf("got unusual pitch %zd for resolution %dx%d\n", fb.pitch, vout_width, vout_height); + LogWarn("got unusual pitch %zd for resolution %dx%d\n", fb.pitch, vout_width, vout_height); vout_pitch = fb.pitch / 2; } else @@ -407,7 +418,7 @@ void *pl_3ds_mmap(unsigned long addr, size_t size, int is_fixed, if (svcControlMemory(&tmp, (void *)custom_map->target_map, (void *)ptr_aligned, size, MEMOP_MAP, 0x3) < 0) { - SysPrintf("could not map memory @0x%08X\n", custom_map->target_map); + LogErr("could not map memory @0x%08X\n", custom_map->target_map); exit(1); } @@ -1080,7 +1091,7 @@ static void save_close(void *file) return; if (fp->pos > r_size) - SysPrintf("ERROR: save buffer overflow detected\n"); + LogErr("ERROR: save buffer overflow detected\n"); else if (fp->is_write && fp->pos < r_size) // make sure we don't save trash in leftover space memset(fp->buf + fp->pos, 0, r_size - fp->pos); @@ -1151,7 +1162,7 @@ void retro_cheat_set(unsigned index, bool enabled, const char *code) finish: if (ret != 0) - SysPrintf("Failed to set cheat %#u\n", index); + LogErr("Failed to set cheat %#u\n", index); else if (index < NumCheats) Cheats[index].Enabled = enabled; free(buf); @@ -1257,7 +1268,7 @@ static bool disk_set_image_index(unsigned int index) if (disks[index].fname == NULL) { - SysPrintf("missing disk #%u\n", index); + LogErr("missing disk #%u\n", index); CDR_shutdown(); // RetroArch specifies "no disk" with index == count, @@ -1266,19 +1277,19 @@ static bool disk_set_image_index(unsigned int index) return true; } - SysPrintf("switching to disk %u: \"%s\" #%d\n", index, + LogErr("switching to disk %u: \"%s\" #%d\n", index, disks[index].fname, disks[index].internal_index); cdrIsoMultidiskSelect = disks[index].internal_index; set_cd_image(disks[index].fname); if (ReloadCdromPlugin() < 0) { - SysPrintf("failed to load cdr plugin\n"); + LogErr("failed to load cdr plugin\n"); return false; } if (CDR_open() < 0) { - SysPrintf("failed to open cdr plugin\n"); + LogErr("failed to open cdr plugin\n"); return false; } @@ -1675,7 +1686,7 @@ bool retro_load_game(const struct retro_game_info *info) if (info == NULL || info->path == NULL) { - SysPrintf("info->path required\n"); + LogErr("info->path required\n"); return false; } @@ -1695,7 +1706,7 @@ bool retro_load_game(const struct retro_game_info *info) { if (!read_m3u(info->path)) { - log_cb(RETRO_LOG_INFO, "failed to read m3u file\n"); + LogErr("failed to read m3u file\n"); return false; } } @@ -1728,7 +1739,7 @@ bool retro_load_game(const struct retro_game_info *info) /* have to reload after set_cd_image for correct cdr plugin */ if (LoadPlugins() == -1) { - log_cb(RETRO_LOG_INFO, "failed to load plugins\n"); + LogErr("failed to load plugins\n"); return false; } @@ -1737,7 +1748,7 @@ bool retro_load_game(const struct retro_game_info *info) if (OpenPlugins() == -1) { - log_cb(RETRO_LOG_INFO, "failed to open plugins\n"); + LogErr("failed to open plugins\n"); return false; } @@ -1796,12 +1807,12 @@ bool retro_load_game(const struct retro_game_info *info) if (ReloadCdromPlugin() < 0) { - log_cb(RETRO_LOG_INFO, "failed to reload cdr plugins\n"); + LogErr("failed to reload cdr plugins\n"); return false; } if (CDR_open() < 0) { - log_cb(RETRO_LOG_INFO, "failed to open cdr plugin\n"); + LogErr("failed to open cdr plugin\n"); return false; } } @@ -1816,7 +1827,7 @@ bool retro_load_game(const struct retro_game_info *info) if (!is_exe && CheckCdrom() == -1) { - log_cb(RETRO_LOG_INFO, "unsupported/invalid CD image: %s\n", info->path); + LogErr("unsupported/invalid CD image: %s\n", info->path); return false; } @@ -1828,7 +1839,7 @@ bool retro_load_game(const struct retro_game_info *info) ret = LoadCdrom(); if (ret != 0) { - log_cb(RETRO_LOG_INFO, "could not load %s (%d)\n", is_exe ? "exe" : "CD", ret); + LogErr("could not load %s (%d)\n", is_exe ? "exe" : "CD", ret); return false; } emu_on_new_cd(0); @@ -2011,6 +2022,30 @@ static void update_variables(bool in_flight) in_enable_vibration = 1; } + var.value = NULL; + var.key = "pcsx_rearmed_analog_combo"; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (strcmp(var.value, "l1+r1+select") == 0) + in_dualshock_analog_combo = (1 << RETRO_DEVICE_ID_JOYPAD_L) | + (1 << RETRO_DEVICE_ID_JOYPAD_R) | (1 << RETRO_DEVICE_ID_JOYPAD_SELECT); + else if (strcmp(var.value, "l1+r1+start") == 0) + in_dualshock_analog_combo = (1 << RETRO_DEVICE_ID_JOYPAD_L) | + (1 << RETRO_DEVICE_ID_JOYPAD_R) | (1 << RETRO_DEVICE_ID_JOYPAD_START); + else if (strcmp(var.value, "l1+r1+l3") == 0) + in_dualshock_analog_combo = (1 << RETRO_DEVICE_ID_JOYPAD_L) | + (1 << RETRO_DEVICE_ID_JOYPAD_R) | (1 << RETRO_DEVICE_ID_JOYPAD_L3); + else if (strcmp(var.value, "l1+r1+r3") == 0) + in_dualshock_analog_combo = (1 << RETRO_DEVICE_ID_JOYPAD_L) | + (1 << RETRO_DEVICE_ID_JOYPAD_R) | (1 << RETRO_DEVICE_ID_JOYPAD_R3); + else if (strcmp(var.value, "l3+r3") == 0) + in_dualshock_analog_combo = (1 << RETRO_DEVICE_ID_JOYPAD_L3) | + (1 << RETRO_DEVICE_ID_JOYPAD_R3); + else + in_dualshock_analog_combo = 0; + } + var.value = NULL; var.key = "pcsx_rearmed_dithering"; @@ -2066,23 +2101,23 @@ static void update_variables(bool in_flight) if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { - if (strcmp(var.value, "disabled") == 0) - pl_rearmed_cbs.gpu_neon.enhancement_no_main = 0; - else if (strcmp(var.value, "enabled") == 0) + if (strcmp(var.value, "enabled") == 0) pl_rearmed_cbs.gpu_neon.enhancement_no_main = 1; + else + pl_rearmed_cbs.gpu_neon.enhancement_no_main = 0; } -#endif var.value = NULL; - var.key = "pcsx_rearmed_duping_enable"; + var.key = "pcsx_rearmed_neon_enhancement_tex_adj"; if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { - if (strcmp(var.value, "disabled") == 0) - duping_enable = false; - else if (strcmp(var.value, "enabled") == 0) - duping_enable = true; + if (strcmp(var.value, "enabled") == 0) + pl_rearmed_cbs.gpu_neon.enhancement_tex_adj = 1; + else + pl_rearmed_cbs.gpu_neon.enhancement_tex_adj = 0; } +#endif var.value = NULL; var.key = "pcsx_rearmed_display_internal_fps"; @@ -2863,13 +2898,13 @@ static void update_input_mouse(int port, int ret) static void update_input(void) { - // reset all keystate, query libretro for keystate int i; int j; + // reset all keystate, query libretro for keystate for (i = 0; i < PORTS_NUMBER; i++) { - int16_t ret = 0; + int32_t ret = 0; int type = in_type[i]; in_keystate[i] = 0; @@ -2878,7 +2913,11 @@ static void update_input(void) continue; if (libretro_supports_bitmasks) + { ret = input_state_cb(i, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_MASK); + // undo int16 sign extension (why input_state_cb returns int16 in the first place?) + ret &= (1 << (RETRO_DEVICE_ID_JOYPAD_R3 + 1)) - 1; + } else { for (j = 0; j < (RETRO_DEVICE_ID_JOYPAD_R3 + 1); j++) @@ -2903,7 +2942,23 @@ static void update_input(void) update_input_mouse(i, ret); break; default: - // Query digital inputs + // dualshock ANALOG toggle? + if (type == PSE_PAD_TYPE_ANALOGPAD && in_dualshock_analog_combo != 0 + && ret == in_dualshock_analog_combo) + { + if (!in_dualshock_toggling) + { + int state = padToggleAnalog(i); + char msg[32]; + snprintf(msg, sizeof(msg), "ANALOG %s", state ? "ON" : "OFF"); + show_notification(msg, 800, 1); + in_dualshock_toggling = true; + } + return; + } + in_dualshock_toggling = false; + + // Set digital inputs for (j = 0; j < RETRO_PSX_MAP_LEN; j++) if (ret & (1 << j)) in_keystate[i] |= retro_psx_map[j]; @@ -3037,7 +3092,7 @@ void retro_run(void) frameskip_counter = 0; } - video_cb((vout_fb_dirty || !vout_can_dupe || !duping_enable) ? vout_buf_ptr : NULL, + video_cb((vout_fb_dirty || !vout_can_dupe) ? vout_buf_ptr : NULL, vout_width, vout_height, vout_pitch * 2); vout_fb_dirty = 0; } @@ -3161,7 +3216,7 @@ static int init_memcards(void) { if (strlen(dir) + strlen(CARD2_FILE) + 2 > sizeof(Config.Mcd2)) { - SysPrintf("Path '%s' is too long. Cannot use memcard 2. Use a shorter path.\n", dir); + LogErr("Path '%s' is too long. Cannot use memcard 2. Use a shorter path.\n", dir); ret = -1; } else @@ -3173,7 +3228,7 @@ static int init_memcards(void) } else { - SysPrintf("Could not get save directory! Could not create memcard 2."); + LogErr("Could not get save directory! Could not create memcard 2."); ret = -1; } } @@ -3288,7 +3343,7 @@ void retro_init(void) ret |= emu_core_init(); if (ret != 0) { - SysPrintf("PCSX init failed.\n"); + LogErr("PCSX init failed.\n"); exit(1); } @@ -3308,6 +3363,8 @@ void retro_init(void) loadPSXBios(); environ_cb(RETRO_ENVIRONMENT_GET_CAN_DUPE, &vout_can_dupe); + if (!vout_can_dupe) + LogWarn("CAN_DUPE reports false\n"); disk_initial_index = 0; disk_initial_path[0] = '\0'; diff --git a/pcsx_rearmed/frontend/libretro_core_options.h b/pcsx_rearmed/frontend/libretro_core_options.h index 0ec6123e..79688de4 100644 --- a/pcsx_rearmed/frontend/libretro_core_options.h +++ b/pcsx_rearmed/frontend/libretro_core_options.h @@ -309,20 +309,6 @@ struct retro_core_option_v2_definition option_defs_us[] = { "enabled", #endif }, - { - "pcsx_rearmed_duping_enable", - "Frame Duping (Speedup)", - NULL, - "When enabled and supported by the libretro frontend, provides a small performance increase by directing the frontend to repeat the previous frame if the core has nothing new to display.", - NULL, - "video", - { - { "disabled", NULL }, - { "enabled", NULL }, - { NULL, NULL }, - }, - "enabled", - }, #ifdef THREAD_RENDERING { "pcsx_rearmed_gpu_thread_rendering", @@ -514,7 +500,21 @@ struct retro_core_option_v2_definition option_defs_us[] = { "pcsx_rearmed_neon_enhancement_no_main", "(GPU) Enhanced Resolution Speed Hack", "Enhanced Resolution Speed Hack", - "Improves performance when 'Enhanced Resolution' is enabled, but reduces compatibility and may cause rendering errors.", + "('Enhanced Resolution' Hack) Improves performance but reduces compatibility and may cause rendering errors.", + NULL, + "gpu_neon", + { + { "disabled", NULL }, + { "enabled", NULL }, + { NULL, NULL }, + }, + "disabled", + }, + { + "pcsx_rearmed_neon_enhancement_tex_adj", + "(GPU) Enhanced Resolution Texture Adjustment", + "Enhanced Resolution Texture Adjustment", + "('Enhanced Resolution' Hack) Attempts to solve some texturing issues in some games, but causes new ones in others.", NULL, "gpu_neon", { @@ -853,6 +853,24 @@ struct retro_core_option_v2_definition option_defs_us[] = { }, "enabled", }, + { + "pcsx_rearmed_analog_combo", + "DualShock Analog Mode Toggle Key Combo", + NULL, + "When the input device type is DualShock, this option allows the emulated DualShock to be toggled between DIGITAL and ANALOG mode like original hardware. You can select the button combination for this.", + NULL, + "input", + { + { "disabled", NULL }, + { "l1+r1+select", "L1 + R1 + Select" }, + { "l1+r1+start", "L1 + R1 + Start" }, + { "l1+r1+l3", "L1 + R1 + L3" }, + { "l1+r1+r3", "L1 + R1 + R3" }, + { "l3+r3", "L3 + R3" }, + { NULL, NULL }, + }, + "l1+r1+select" + }, { "pcsx_rearmed_multitap", "Multitap Mode", diff --git a/pcsx_rearmed/frontend/libretro_core_options_intl.h b/pcsx_rearmed/frontend/libretro_core_options_intl.h index d6658222..5e74450a 100644 --- a/pcsx_rearmed/frontend/libretro_core_options_intl.h +++ b/pcsx_rearmed/frontend/libretro_core_options_intl.h @@ -276,18 +276,6 @@ struct retro_core_option_v2_definition option_defs_tr[] = { }, #endif /* GPU_NEON */ - { - "pcsx_rearmed_duping_enable", - "Frame Duping", - NULL, - "Yeni bir veri yoksa, bir hızlandırma, son kareyi yeniden çizer/yeniden kullanır.", - NULL, - NULL, - { - { NULL, NULL }, - }, - NULL - }, { "pcsx_rearmed_display_internal_fps", "Dahili FPS'yi görüntüle", diff --git a/pcsx_rearmed/frontend/main.c b/pcsx_rearmed/frontend/main.c index cec1fbbf..53f31b0a 100644 --- a/pcsx_rearmed/frontend/main.c +++ b/pcsx_rearmed/frontend/main.c @@ -288,6 +288,10 @@ void do_emu_action(void) SysMessage("GPU_open returned %d", ret); } return; + case SACTION_ANALOG_TOGGLE: + ret = padToggleAnalog(0); + snprintf(hud_msg, sizeof(hud_msg), "ANALOG %s", ret ? "ON" : "OFF"); + break; #endif default: return; @@ -590,6 +594,7 @@ int main(int argc, char *argv[]) { char file[MAXPATHLEN] = ""; char path[MAXPATHLEN]; + char isofilename[MAXPATHLEN]; const char *cdfile = NULL; const char *loadst_f = NULL; int psxout = 0; @@ -608,8 +613,6 @@ int main(int argc, char *argv[]) SysPrintf("Using config file %s.\n", cfgfile_basename); } else if (!strcmp(argv[i], "-cdfile")) { - char isofilename[MAXPATHLEN]; - if (i+1 >= argc) break; strncpy(isofilename, argv[++i], MAXPATHLEN); if (isofilename[0] != '/') { diff --git a/pcsx_rearmed/frontend/main.h b/pcsx_rearmed/frontend/main.h index 22053bbc..98b0f370 100644 --- a/pcsx_rearmed/frontend/main.h +++ b/pcsx_rearmed/frontend/main.h @@ -79,6 +79,7 @@ enum sched_action { SACTION_GUN_A, SACTION_GUN_B, SACTION_GUN_TRIGGER2, + SACTION_ANALOG_TOGGLE, }; #define SACTION_GUN_MASK (0x0f << SACTION_GUN_TRIGGER) diff --git a/pcsx_rearmed/frontend/menu.c b/pcsx_rearmed/frontend/menu.c index 9200e10d..51cb3771 100644 --- a/pcsx_rearmed/frontend/menu.c +++ b/pcsx_rearmed/frontend/menu.c @@ -217,7 +217,7 @@ static int optional_cdimg_filter(struct dirent **namelist, int count, const char *basedir) { const char *ext, *p; - char buf[256], buf2[256]; + char buf[256], buf2[257]; int i, d, ret, good_cue; struct STAT statf; FILE *f; @@ -316,14 +316,16 @@ static void menu_sync_config(void) switch (in_type_sel1) { case 1: in_type[0] = PSE_PAD_TYPE_ANALOGPAD; break; - case 2: in_type[0] = PSE_PAD_TYPE_NEGCON; break; - case 3: in_type[0] = PSE_PAD_TYPE_NONE; break; + case 2: in_type[0] = PSE_PAD_TYPE_GUNCON; break; + case 3: in_type[0] = PSE_PAD_TYPE_GUN; break; + case 4: in_type[0] = PSE_PAD_TYPE_NONE; break; default: in_type[0] = PSE_PAD_TYPE_STANDARD; } switch (in_type_sel2) { case 1: in_type[1] = PSE_PAD_TYPE_ANALOGPAD; break; - case 2: in_type[1] = PSE_PAD_TYPE_NEGCON; break; - case 3: in_type[1] = PSE_PAD_TYPE_NONE; break; + case 2: in_type[1] = PSE_PAD_TYPE_GUNCON; break; + case 3: in_type[1] = PSE_PAD_TYPE_GUN; break; + case 4: in_type[1] = PSE_PAD_TYPE_NONE; break; default: in_type[1] = PSE_PAD_TYPE_STANDARD; } if (in_evdev_allow_abs_only != allow_abs_only_old) { @@ -448,6 +450,7 @@ static const struct { CE_INTVAL_P(gpu_neon.allow_interlace), CE_INTVAL_P(gpu_neon.enhancement_enable), CE_INTVAL_P(gpu_neon.enhancement_no_main), + CE_INTVAL_P(gpu_neon.enhancement_tex_adj), CE_INTVAL_P(gpu_peopsgl.bDrawDither), CE_INTVAL_P(gpu_peopsgl.iFilterType), CE_INTVAL_P(gpu_peopsgl.iFrameTexType), @@ -499,6 +502,13 @@ static void make_cfg_fname(char *buf, size_t size, int is_game) static void keys_write_all(FILE *f); static char *mystrip(char *str); +static void write_u32_value(FILE *f, u32 v) +{ + if (v > 7) + fprintf(f, "0x"); + fprintf(f, "%x\n", v); +} + static int menu_write_config(int is_game) { char cfgfile[MAXPATHLEN]; @@ -521,13 +531,13 @@ static int menu_write_config(int is_game) fprintf(f, "%s\n", (char *)config_data[i].val); break; case 1: - fprintf(f, "%x\n", *(u8 *)config_data[i].val); + write_u32_value(f, *(u8 *)config_data[i].val); break; case 2: - fprintf(f, "%x\n", *(u16 *)config_data[i].val); + write_u32_value(f, *(u16 *)config_data[i].val); break; case 4: - fprintf(f, "%x\n", *(u32 *)config_data[i].val); + write_u32_value(f, *(u32 *)config_data[i].val); break; default: printf("menu_write_config: unhandled len %d for %s\n", @@ -894,6 +904,7 @@ me_bind_action emuctrl_actions[] = { "Volume Up ", 1 << SACTION_VOLUME_UP }, { "Volume Down ", 1 << SACTION_VOLUME_DOWN }, #endif + { "Analog toggle ", 1 << SACTION_ANALOG_TOGGLE }, { NULL, 0 } }; @@ -1210,6 +1221,7 @@ static const char *men_in_type_sel[] = { "Standard (SCPH-1080)", "Analog (SCPH-1150)", "GunCon", + "Konami Gun", "None", NULL }; @@ -1272,24 +1284,47 @@ static const char h_cscaler[] = "Displays the scaler layer, you can resize it\ static const char h_soft_filter[] = "Works only if game uses low resolution modes"; static const char h_gamma[] = "Gamma/brightness adjustment (default 100)"; #ifdef __ARM_NEON__ +static const char *men_scanlines[] = { "OFF", "1", "2", "3", NULL }; static const char h_scanline_l[] = "Scanline brightness, 0-100%"; #endif static int menu_loop_cscaler(int id, int keys) { + void *saved_layer = NULL; + size_t saved_layer_size = 0; + int was_layer_clipped = 0; unsigned int inp; + if (!pl_vout_buf) + return -1; + g_scaler = SCALE_CUSTOM; + saved_layer_size = last_vout_w * last_vout_h * last_vout_bpp / 8; + saved_layer = malloc(saved_layer_size); + if (saved_layer) + memcpy(saved_layer, pl_vout_buf, saved_layer_size); plat_gvideo_open(Config.PsxType); + menu_draw_begin(0, 1); + memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2); + menu_draw_end(); + for (;;) { - menu_draw_begin(0, 1); - memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2); - text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y); - text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h); - menu_draw_end(); + if (saved_layer && last_vout_bpp == 16) { + int top_x = max(0, -g_layer_x * last_vout_h / 800) + 1; + int top_y = max(0, -g_layer_y * last_vout_h / 480) + 1; + char text[128]; + memcpy(pl_vout_buf, saved_layer, saved_layer_size); + snprintf(text, sizeof(text), "%d,%d %dx%d", + g_layer_x, g_layer_y, g_layer_w, g_layer_h); + basic_text_out16_nf(pl_vout_buf, last_vout_w, + top_x, top_y, text); + basic_text_out16_nf(pl_vout_buf, last_vout_w, 2, + last_vout_h - 20, "d-pad: resize, R+d-pad: move"); + pl_vout_buf = plat_gvideo_flip(); + } inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT |PBTN_R|PBTN_MOK|PBTN_MBACK, NULL, 40); @@ -1307,22 +1342,30 @@ static int menu_loop_cscaler(int id, int keys) break; if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) { - if (g_layer_x < 0) g_layer_x = 0; - if (g_layer_x > 640) g_layer_x = 640; - if (g_layer_y < 0) g_layer_y = 0; - if (g_layer_y > 420) g_layer_y = 420; - if (g_layer_w < 160) g_layer_w = 160; - if (g_layer_h < 60) g_layer_h = 60; - if (g_layer_x + g_layer_w > 800) - g_layer_w = 800 - g_layer_x; - if (g_layer_y + g_layer_h > 480) - g_layer_h = 480 - g_layer_y; + int layer_clipped = 0; + g_layer_x = max(-320, min(g_layer_x, 640)); + g_layer_y = max(-240, min(g_layer_y, 400)); + g_layer_w = max(160, g_layer_w); + g_layer_h = max( 60, g_layer_h); + if (g_layer_x < 0 || g_layer_x + g_layer_w > 800) + layer_clipped = 1; + if (g_layer_w > 800+400) + g_layer_w = 800+400; + if (g_layer_y < 0 || g_layer_y + g_layer_h > 480) + layer_clipped = 1; + if (g_layer_h > 480+360) + g_layer_h = 480+360; // resize the layer plat_gvideo_open(Config.PsxType); + if (layer_clipped || was_layer_clipped) + pl_vout_buf = plat_gvideo_set_mode(&last_vout_w, + &last_vout_h, &last_vout_bpp); + was_layer_clipped = layer_clipped; } } plat_gvideo_close(); + free(saved_layer); return 0; } @@ -1336,7 +1379,7 @@ static menu_entry e_menu_gfx_options[] = 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_enum ("Scanlines", MA_OPT_SCANLINES, scanlines, men_scanlines), 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), @@ -1372,6 +1415,7 @@ static menu_entry e_menu_plugin_gpu_neon[] = mee_enum ("Enable interlace mode", 0, pl_rearmed_cbs.gpu_neon.allow_interlace, men_gpu_interlace), mee_onoff_h ("Enhanced resolution", 0, pl_rearmed_cbs.gpu_neon.enhancement_enable, 1, h_gpu_neon_enhanced), mee_onoff_h ("Enhanced res. speed hack", 0, pl_rearmed_cbs.gpu_neon.enhancement_no_main, 1, h_gpu_neon_enhanced_hack), + mee_onoff ("Enh. res. texture adjust", 0, pl_rearmed_cbs.gpu_neon.enhancement_tex_adj, 1), mee_end, }; @@ -1682,6 +1726,7 @@ static const char h_confirm_save[] = "Ask for confirmation when overwriting s static const char h_restore_def[] = "Switches back to default / recommended\n" "configuration"; static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n"; +static const char h_sputhr[] = "Warning: has some known bugs\n"; static menu_entry e_menu_options[] = { @@ -1692,9 +1737,9 @@ static menu_entry e_menu_options[] = mee_enum ("Region", 0, region, men_region), mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000), #ifdef C64X_DSP - mee_onoff ("Use C64x DSP for sound", MA_OPT_SPU_THREAD, spu_config.iUseThread, 1), + mee_onoff_h ("Use C64x DSP for sound", MA_OPT_SPU_THREAD, spu_config.iUseThread, 1, h_sputhr), #else - mee_onoff ("Threaded SPU", MA_OPT_SPU_THREAD, spu_config.iUseThread, 1), + mee_onoff_h ("Threaded SPU", MA_OPT_SPU_THREAD, spu_config.iUseThread, 1, h_sputhr), #endif mee_handler_id("[Display]", MA_OPT_DISP_OPTS, menu_loop_gfx_options), mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options), diff --git a/pcsx_rearmed/frontend/pl_gun_ts.c b/pcsx_rearmed/frontend/pl_gun_ts.c index 6c05b7c3..6e7fa940 100644 --- a/pcsx_rearmed/frontend/pl_gun_ts.c +++ b/pcsx_rearmed/frontend/pl_gun_ts.c @@ -54,7 +54,7 @@ int pl_gun_ts_update_raw(struct tsdev *ts, int *x, int *y, int *p) gun_y = (sy - ts_offs_y) * ts_multiplier_y >> 10; limit(gun_x, 0, 1023); limit(gun_y, 0, 1023); - if (sp && !(g_opts & OPT_TSGUN_NOTRIGGER)) + if (sp) gun_in |= 1; else gun_in &= ~1; @@ -78,7 +78,7 @@ void pl_gun_ts_update(struct tsdev *ts, int *x, int *y, int *in) *x = gun_x; *y = gun_y; - *in = gun_in | in_state_gun; + *in = gun_in; } void pl_set_gun_rect(int x, int y, int w, int h) diff --git a/pcsx_rearmed/frontend/plat_omap.c b/pcsx_rearmed/frontend/plat_omap.c index c4bff313..2dab7a16 100644 --- a/pcsx_rearmed/frontend/plat_omap.c +++ b/pcsx_rearmed/frontend/plat_omap.c @@ -79,11 +79,21 @@ static int omap_setup_layer_(int fd, int enabled, int x, int y, int w, int h) static int omap_enable_layer(int enabled) { + int x = g_layer_x, y = g_layer_y; + int w = g_layer_w, h = g_layer_h; + + // it's not allowed for the layer to be partially offscreen, + // instead it is faked by plat_gvideo_set_mode() + if (x < 0) { w += x; x = 0; } + if (y < 0) { h += y; y = 0; } + if (x + w > 800) w = 800 - x; + if (y + h > 480) h = 480 - y; + if (enabled) - pl_set_gun_rect(g_layer_x, g_layer_y, g_layer_w, g_layer_h); + pl_set_gun_rect(x, y, w, h); - return omap_setup_layer_(vout_fbdev_get_fd(layer_fb), enabled, - g_layer_x, g_layer_y, g_layer_w, g_layer_h); + return omap_setup_layer_(vout_fbdev_get_fd(layer_fb), + enabled, x, y, w, h); } void plat_omap_gvideo_open(void) @@ -101,15 +111,25 @@ void *plat_gvideo_set_mode(int *w_in, int *h_in, int *bpp) void *buf; if (g_scaler == SCALE_1_1 || g_scaler == SCALE_2_2) { - if (w > g_menuscreen_w) { + if (w > g_menuscreen_w) l = r = (w - g_menuscreen_w) / 2; - w -= l + r; - } - if (h > g_menuscreen_h) { + if (h > g_menuscreen_h) t = b = (h - g_menuscreen_h) / 2; - h -= t + b; - } } + else if (g_scaler == SCALE_CUSTOM) { + int right = g_layer_x + g_layer_w; + int bottom = g_layer_y + g_layer_h; + if (g_layer_x < 0) + l = -g_layer_x * w / g_menuscreen_w; + if (g_layer_y < 0) + t = -g_layer_y * h / g_menuscreen_h; + if (right > g_menuscreen_w) + r = (right - g_menuscreen_w) * w / g_menuscreen_w; + if (bottom > g_menuscreen_h) + b = (bottom - g_menuscreen_h) * h / g_menuscreen_h; + } + w -= l + r; + h -= t + b; buf = vout_fbdev_resize(layer_fb, w, h, *bpp, l, r, t, b, 3); diff --git a/pcsx_rearmed/frontend/plugin.c b/pcsx_rearmed/frontend/plugin.c index 88d756eb..c400165f 100644 --- a/pcsx_rearmed/frontend/plugin.c +++ b/pcsx_rearmed/frontend/plugin.c @@ -46,20 +46,7 @@ static long CALLBACK CDRgetTE(unsigned char _, unsigned char *__, unsigned char static void CALLBACK GPUdisplayText(char *_) { return; } /* SPU */ -extern long CALLBACK SPUopen(void); -extern long CALLBACK SPUinit(void); -extern long CALLBACK SPUshutdown(void); -extern long CALLBACK SPUclose(void); -extern void CALLBACK SPUwriteRegister(unsigned long, unsigned short, unsigned int); -extern unsigned short CALLBACK SPUreadRegister(unsigned long, unsigned int); -extern void CALLBACK SPUwriteDMAMem(unsigned short *, int, unsigned int); -extern void CALLBACK SPUreadDMAMem(unsigned short *, int, unsigned int); -extern void CALLBACK SPUplayADPCMchannel(void *, unsigned int, int); -extern void CALLBACK SPUregisterCallback(void (*cb)(int)); -extern void CALLBACK SPUregisterScheduleCb(void (*cb)(unsigned int)); -extern long CALLBACK SPUfreeze(unsigned int, void *, unsigned int); -extern void CALLBACK SPUasync(unsigned int, unsigned int); -extern int CALLBACK SPUplayCDDAchannel(short *, int, unsigned int, int); +#include "../plugins/dfsound/spu.h" /* PAD */ static long CALLBACK PADinit(long _) { return 0; } @@ -135,7 +122,7 @@ extern void GPUwriteDataMem(uint32_t *, int); extern uint32_t GPUreadStatus(void); extern uint32_t GPUreadData(void); extern void GPUreadDataMem(uint32_t *, int); -extern long GPUdmaChain(uint32_t *, uint32_t, uint32_t *); +extern long GPUdmaChain(uint32_t *, uint32_t, uint32_t *, int32_t *); extern void GPUupdateLace(void); extern long GPUfreeze(uint32_t, void *); extern void GPUvBlank(int, int); @@ -191,6 +178,7 @@ static const struct { DIRECT_SPU(SPUregisterScheduleCb), DIRECT_SPU(SPUasync), DIRECT_SPU(SPUplayCDDAchannel), + DIRECT_SPU(SPUsetCDvol), /* PAD */ DIRECT_PAD(PADinit), DIRECT_PAD(PADshutdown), @@ -231,8 +219,6 @@ static const struct { DIRECT_GPU(GPUkeypressed), DIRECT_GPU(GPUmakeSnapshot), DIRECT_GPU(GPUconfigure), - DIRECT_GPU(GPUtest), - DIRECT_GPU(GPUabout), DIRECT_GPU(GPUgetScreenPic), DIRECT_GPU(GPUshowScreenPic), */ diff --git a/pcsx_rearmed/frontend/plugin_lib.c b/pcsx_rearmed/frontend/plugin_lib.c index 50aba227..0deab157 100644 --- a/pcsx_rearmed/frontend/plugin_lib.c +++ b/pcsx_rearmed/frontend/plugin_lib.c @@ -34,6 +34,7 @@ #include "../libpcsxcore/new_dynarec/new_dynarec.h" #include "../libpcsxcore/psxmem_map.h" #include "../libpcsxcore/gpu.h" +#include "../libpcsxcore/r3000a.h" #define HUD_HEIGHT 10 @@ -46,7 +47,6 @@ int in_adev[2] = { -1, -1 }, in_adev_axis[2][2] = {{ 0, 1 }, { 0, 1 }}; int in_adev_is_nublike[2]; unsigned short in_keystate[8]; int in_mouse[8][2]; -int in_state_gun; int in_enable_vibration; void *tsdev; void *pl_vout_buf; @@ -227,12 +227,12 @@ static void update_layer_size(int w, int h) break; } - g_layer_x = g_menuscreen_w / 2 - g_layer_w / 2; - g_layer_y = g_menuscreen_h / 2 - g_layer_h / 2; - if (g_layer_x < 0) g_layer_x = 0; - if (g_layer_y < 0) g_layer_y = 0; - if (g_layer_w > g_menuscreen_w) g_layer_w = g_menuscreen_w; - if (g_layer_h > g_menuscreen_h) g_layer_h = g_menuscreen_h; + if (g_scaler != SCALE_CUSTOM) { + g_layer_x = g_menuscreen_w / 2 - g_layer_w / 2; + g_layer_y = g_menuscreen_h / 2 - g_layer_h / 2; + } + if (g_layer_w > g_menuscreen_w * 2) g_layer_w = g_menuscreen_w * 2; + if (g_layer_h > g_menuscreen_h * 2) g_layer_h = g_menuscreen_h * 2; } // XXX: this is platform specific really @@ -338,7 +338,7 @@ static void pl_vout_flip(const void *vram, int stride, int bgr24, doffs = xoffs + y * dstride; if (dims_changed) - flip_clear_counter = 2; + flip_clear_counter = 3; if (flip_clear_counter > 0) { if (pl_plat_clear) @@ -391,17 +391,21 @@ static void pl_vout_flip(const void *vram, int stride, int bgr24, } else if (scanlines != 0 && scanline_level != 100) { - int l = scanline_level * 2048 / 100; + int h2, l = scanline_level * 2048 / 100; int stride_0 = pl_vout_scale_h >= 2 ? 0 : stride; h1 *= pl_vout_scale_h; - for (; h1 >= 2; h1 -= 2) + while (h1 > 0) { - bgr555_to_rgb565(dest, src, w * 2); - dest += dstride * 2, src += stride_0; + for (h2 = scanlines; h2 > 0 && h1 > 0; h2--, h1--) { + bgr555_to_rgb565(dest, src, w * 2); + dest += dstride * 2, src += stride_0; + } - bgr555_to_rgb565_b(dest, src, w * 2, l); - dest += dstride * 2, src += stride; + for (h2 = scanlines; h2 > 0 && h1 > 0; h2--, h1--) { + bgr555_to_rgb565_b(dest, src, w * 2, l); + dest += dstride * 2, src += stride; + } } } #endif @@ -609,12 +613,14 @@ static void update_input(void) { int actions[IN_BINDTYPE_COUNT] = { 0, }; unsigned int emu_act; + int in_state_gun; + int i; in_update(actions); if (in_type[0] == PSE_PAD_TYPE_ANALOGJOY || in_type[0] == PSE_PAD_TYPE_ANALOGPAD) update_analogs(); emu_act = actions[IN_BINDTYPE_EMU]; - in_state_gun = (emu_act & SACTION_GUN_MASK) >> SACTION_GUN_TRIGGER; + in_state_gun = emu_act & SACTION_GUN_MASK; emu_act &= ~SACTION_GUN_MASK; if (emu_act) { @@ -625,12 +631,35 @@ static void update_input(void) } emu_set_action(emu_act); - in_keystate[0] = actions[IN_BINDTYPE_PLAYER12]; + in_keystate[0] = actions[IN_BINDTYPE_PLAYER12] & 0xffff; + in_keystate[1] = (actions[IN_BINDTYPE_PLAYER12] >> 16) & 0xffff; - // fixme - //if (in_type[0] == PSE_PAD_TYPE_GUNCON && tsdev) - // pl_gun_ts_update(tsdev, xn, yn, in); - // in_analog_left[0][0] = xn + if (tsdev) for (i = 0; i < 2; i++) { + int in = 0, x = 0, y = 0, trigger;; + if (in_type[i] != PSE_PAD_TYPE_GUN + && in_type[i] != PSE_PAD_TYPE_GUNCON) + continue; + trigger = in_type[i] == PSE_PAD_TYPE_GUN + ? (1 << DKEY_SQUARE) : (1 << DKEY_CIRCLE); + + pl_gun_ts_update(tsdev, &x, &y, &in); + in_analog_left[i][0] = 65536; + in_analog_left[i][1] = 65536; + if (in && !(in_state_gun & (1 << SACTION_GUN_TRIGGER2))) { + in_analog_left[i][0] = x; + in_analog_left[i][1] = y; + if (!(g_opts & OPT_TSGUN_NOTRIGGER)) + in_state_gun |= (1 << SACTION_GUN_TRIGGER); + } + in_keystate[i] = 0; + if (in_state_gun & ((1 << SACTION_GUN_TRIGGER) + | (1 << SACTION_GUN_TRIGGER2))) + in_keystate[i] |= trigger; + if (in_state_gun & (1 << SACTION_GUN_A)) + in_keystate[i] |= (1 << DKEY_START); + if (in_state_gun & (1 << SACTION_GUN_B)) + in_keystate[i] |= (1 << DKEY_CROSS); + } } #else /* MAEMO */ extern void update_input(void); @@ -638,6 +667,13 @@ extern void update_input(void); void pl_gun_byte2(int port, unsigned char byte) { + if (!tsdev || in_type[port] != PSE_PAD_TYPE_GUN || !(byte & 0x10)) + return; + if (in_analog_left[port][0] == 65536) + return; + + psxScheduleIrq10(4, in_analog_left[port][0] * 1629 / 1024, + in_analog_left[port][1] * psx_h / 1024); } #define MAX_LAG_FRAMES 3 diff --git a/pcsx_rearmed/frontend/plugin_lib.h b/pcsx_rearmed/frontend/plugin_lib.h index 5b4af659..5733ca24 100644 --- a/pcsx_rearmed/frontend/plugin_lib.h +++ b/pcsx_rearmed/frontend/plugin_lib.h @@ -23,7 +23,6 @@ enum { DKEY_CROSS, DKEY_SQUARE, }; -extern int in_state_gun; extern int in_type[8]; extern int multitap1; extern int multitap2; @@ -86,6 +85,7 @@ struct rearmed_cbs { int enhancement_enable; int enhancement_no_main; int allow_dithering; + int enhancement_tex_adj; } gpu_neon; struct { int iUseDither; diff --git a/pcsx_rearmed/include/psemu_plugin_defs.h b/pcsx_rearmed/include/psemu_plugin_defs.h index 3f4d21b2..4e69b167 100644 --- a/pcsx_rearmed/include/psemu_plugin_defs.h +++ b/pcsx_rearmed/include/psemu_plugin_defs.h @@ -228,9 +228,11 @@ typedef struct unsigned char padMode; // 0 : digital 1: analog unsigned char cmd4dConfig[6]; unsigned int lastUseFrame; - unsigned int digitalModeFrames; + unsigned int unused; unsigned char configModeUsed; - unsigned char padding[3]; + unsigned char autoAnalogTried; + unsigned char userToggled; + unsigned char padding; } ds; unsigned char multitapLongModeEnabled; unsigned char padding2; diff --git a/pcsx_rearmed/libpcsxcore/cdrom.c b/pcsx_rearmed/libpcsxcore/cdrom.c index 7431a926..872cc0c8 100644 --- a/pcsx_rearmed/libpcsxcore/cdrom.c +++ b/pcsx_rearmed/libpcsxcore/cdrom.c @@ -113,7 +113,7 @@ static struct { u8 unused7; - u8 DriveState; + u8 DriveState; // enum drive_state u8 FastForward; u8 FastBackward; u8 errorRetryhack; @@ -222,11 +222,14 @@ unsigned char Test23[] = { 0x43, 0x58, 0x44, 0x32, 0x39 ,0x34, 0x30, 0x51 }; #define SUBQ_FORWARD_SECTORS 2u enum drive_state { - DRIVESTATE_STANDBY = 0, // pause, play, read + DRIVESTATE_STANDBY = 0, // different from paused DRIVESTATE_LID_OPEN, DRIVESTATE_RESCAN_CD, DRIVESTATE_PREPARE_CD, DRIVESTATE_STOPPED, + DRIVESTATE_PAUSED, + DRIVESTATE_PLAY_READ, + DRIVESTATE_SEEK, }; static struct CdrStat stat; @@ -341,26 +344,22 @@ void cdrLidSeekInterrupt(void) // 02, 12, 10 if (!(cdr.StatP & STATUS_SHELLOPEN)) { + StopReading(); SetPlaySeekRead(cdr.StatP, 0); cdr.StatP |= STATUS_SHELLOPEN; // IIRC this sometimes doesn't happen on real hw // (when lots of commands are sent?) - if (cdr.Reading) { - StopReading(); - SetResultSize(2); - cdr.Result[0] = cdr.StatP | STATUS_SEEKERROR; - cdr.Result[1] = ERROR_SHELLOPEN; - setIrq(DiskError, 0x1006); - } + SetResultSize(2); + cdr.Result[0] = cdr.StatP | STATUS_SEEKERROR; + cdr.Result[1] = ERROR_SHELLOPEN; if (cdr.CmdInProgress) { psxRegs.interrupt &= ~(1 << PSXINT_CDR); cdr.CmdInProgress = 0; - SetResultSize(2); cdr.Result[0] = cdr.StatP | STATUS_ERROR; cdr.Result[1] = ERROR_NOTREADY; - setIrq(DiskError, 0x1007); } + setIrq(DiskError, 0x1006); set_event(PSXINT_CDRLID, cdReadTime * 30); break; @@ -537,6 +536,7 @@ static void cdrPlayInterrupt_Autopause() StopCdda(); SetPlaySeekRead(cdr.StatP, 0); + cdr.DriveState = DRIVESTATE_PAUSED; } else if ((cdr.Mode & MODE_REPORT) && !cdr.ReportDelay && ((cdr.subq.Absolute[2] & 0x0f) == 0 || cdr.FastForward || cdr.FastBackward)) @@ -585,16 +585,17 @@ static int cdrSeekTime(unsigned char *target) // need this stupidly long penalty or else Spyro2 intro desyncs // note: if misapplied this breaks MGS cutscenes among other things - if (cyclesSinceRS > cdReadTime * 50) + if (cdr.DriveState == DRIVESTATE_PAUSED && cyclesSinceRS > cdReadTime * 50) seekTime += cdReadTime * 25; // Transformers Beast Wars Transmetals does Setloc(x),SeekL,Setloc(x),ReadN // and then wants some slack time - else if (cyclesSinceRS < cdReadTime *3/2) + else if (cdr.DriveState == DRIVESTATE_PAUSED || cyclesSinceRS < cdReadTime *3/2) seekTime += cdReadTime; seekTime = MIN_VALUE(seekTime, PSXCLK * 2 / 3); - CDR_LOG("seek: %.2f %.2f (%.2f)\n", (float)seekTime / PSXCLK, - (float)seekTime / cdReadTime, (float)cyclesSinceRS / cdReadTime); + CDR_LOG("seek: %.2f %.2f (%.2f) st %d\n", (float)seekTime / PSXCLK, + (float)seekTime / cdReadTime, (float)cyclesSinceRS / cdReadTime, + cdr.DriveState); return seekTime; } @@ -628,7 +629,6 @@ static u32 cdrAlignTimingHack(u32 cycles) static void cdrUpdateTransferBuf(const u8 *buf); static void cdrReadInterrupt(void); static void cdrPrepCdda(s16 *buf, int samples); -static void cdrAttenuate(s16 *buf, int samples, int stereo); static void msfiAdd(u8 *msfi, u32 count) { @@ -672,12 +672,14 @@ void cdrPlayReadInterrupt(void) CDR_LOG("CDDA - %02d:%02d:%02d m %02x\n", cdr.SetSectorPlay[0], cdr.SetSectorPlay[1], cdr.SetSectorPlay[2], cdr.Mode); + cdr.DriveState = DRIVESTATE_PLAY_READ; SetPlaySeekRead(cdr.StatP, STATUS_PLAY); if (memcmp(cdr.SetSectorPlay, cdr.SetSectorEnd, 3) == 0) { CDR_LOG_I("end stop\n"); StopCdda(); SetPlaySeekRead(cdr.StatP, 0); cdr.TrackChanged = TRUE; + cdr.DriveState = DRIVESTATE_PAUSED; } else { CDR_readCDDA(cdr.SetSectorPlay[0], cdr.SetSectorPlay[1], cdr.SetSectorPlay[2], (u8 *)read_buf); @@ -686,9 +688,8 @@ void cdrPlayReadInterrupt(void) if (!cdr.IrqStat && (cdr.Mode & (MODE_AUTOPAUSE|MODE_REPORT))) cdrPlayInterrupt_Autopause(); - if (!cdr.Muted && cdr.Play && !Config.Cdda) { + if (cdr.Play && !Config.Cdda) { cdrPrepCdda(read_buf, CD_FRAMESIZE_RAW / 4); - cdrAttenuate(read_buf, CD_FRAMESIZE_RAW / 4, 1); SPU_playCDDAchannel(read_buf, CD_FRAMESIZE_RAW, psxRegs.cycle, 0); } @@ -700,6 +701,30 @@ void cdrPlayReadInterrupt(void) CDRPLAYREAD_INT(cdReadTime, 0); } +static void softReset(void) +{ + CDR_getStatus(&stat); + if (stat.Status & STATUS_SHELLOPEN) { + cdr.DriveState = DRIVESTATE_LID_OPEN; + cdr.StatP = STATUS_SHELLOPEN; + } + else if (CdromId[0] == '\0') { + cdr.DriveState = DRIVESTATE_STOPPED; + cdr.StatP = 0; + } + else { + cdr.DriveState = DRIVESTATE_STANDBY; + cdr.StatP = STATUS_ROTATING; + } + + cdr.FifoOffset = DATA_SIZE; // fifo empty + cdr.LocL[0] = LOCL_INVALID; + cdr.Mode = MODE_SIZE_2340; + cdr.Muted = FALSE; + SPU_setCDvol(cdr.AttenuatorLeftToLeft, cdr.AttenuatorLeftToRight, + cdr.AttenuatorRightToLeft, cdr.AttenuatorRightToRight, psxRegs.cycle); +} + #define CMD_PART2 0x100 #define CMD_WHILE_NOT_READY 0x200 @@ -714,6 +739,7 @@ void cdrInterrupt(void) { int read_ok; u16 not_ready = 0; u8 IrqStat = Acknowledge; + u8 DriveStateOld; u16 Cmd; int i; @@ -861,6 +887,7 @@ void cdrInterrupt(void) { // BIOS player - set flag again cdr.Play = TRUE; + cdr.DriveState = DRIVESTATE_PLAY_READ; CDRPLAYREAD_INT(cdReadTime + seekTime, 1); start_rotating = 1; @@ -888,6 +915,7 @@ void cdrInterrupt(void) { error = ERROR_BAD_ARGNUM; goto set_error; } + cdr.DriveState = DRIVESTATE_STANDBY; second_resp_time = cdReadTime * 125 / 2; start_rotating = 1; break; @@ -913,7 +941,7 @@ void cdrInterrupt(void) { cdr.LocL[0] = LOCL_INVALID; second_resp_time = 0x800; - if (cdr.DriveState == DRIVESTATE_STANDBY) + if (cdr.DriveState != DRIVESTATE_STOPPED) second_resp_time = cdReadTime * 30 / 2; cdr.DriveState = DRIVESTATE_STOPPED; @@ -924,6 +952,11 @@ void cdrInterrupt(void) { break; case CdlPause: + if (cdr.AdpcmActive) { + cdr.AdpcmActive = 0; + cdr.Xa.nsamples = 0; + SPU_playADPCMchannel(&cdr.Xa, psxRegs.cycle, 1); // flush adpcm + } StopCdda(); StopReading(); @@ -956,6 +989,16 @@ void cdrInterrupt(void) { second_resp_time = (((cdr.Mode & MODE_SPEED) ? 1 : 2) * 1097107); } SetPlaySeekRead(cdr.StatP, 0); + DriveStateOld = cdr.DriveState; + cdr.DriveState = DRIVESTATE_PAUSED; + if (DriveStateOld == DRIVESTATE_SEEK) { + // According to Duckstation this fails, but the + // exact conditions and effects are not clear. + // Moto Racer World Tour seems to rely on this. + // For now assume pause works anyway, just errors out. + error = ERROR_NOTREADY; + goto set_error; + } break; case CdlPause + CMD_PART2: @@ -964,12 +1007,11 @@ void cdrInterrupt(void) { case CdlReset: case CdlReset + CMD_WHILE_NOT_READY: + // note: nocash and Duckstation calls this 'Init', but + // the official SDK calls it 'Reset', and so do we StopCdda(); StopReading(); - SetPlaySeekRead(cdr.StatP, 0); - cdr.LocL[0] = LOCL_INVALID; - cdr.Muted = FALSE; - cdr.Mode = MODE_SIZE_2340; /* This fixes This is Football 2, Pooh's Party lockups */ + softReset(); second_resp_time = not_ready ? 70000 : 4100000; start_rotating = 1; break; @@ -981,10 +1023,13 @@ void cdrInterrupt(void) { case CdlMute: cdr.Muted = TRUE; + SPU_setCDvol(0, 0, 0, 0, psxRegs.cycle); break; case CdlDemute: cdr.Muted = FALSE; + SPU_setCDvol(cdr.AttenuatorLeftToLeft, cdr.AttenuatorLeftToRight, + cdr.AttenuatorRightToLeft, cdr.AttenuatorRightToRight, psxRegs.cycle); break; case CdlSetfilter: @@ -1063,6 +1108,7 @@ void cdrInterrupt(void) { seekTime = cdrSeekTime(cdr.SetSector); memcpy(cdr.SetSectorPlay, cdr.SetSector, 4); + cdr.DriveState = DRIVESTATE_SEEK; /* Crusaders of Might and Magic = 0.5x-4x - fix cutscene speech start @@ -1091,6 +1137,7 @@ void cdrInterrupt(void) { if (read_ok && (buf = CDR_getBuffer())) memcpy(cdr.LocL, buf, 8); UpdateSubq(cdr.SetSectorPlay); + cdr.DriveState = DRIVESTATE_STANDBY; cdr.TrackChanged = FALSE; cdr.LastReadSeekCycles = psxRegs.cycle; break; @@ -1198,6 +1245,7 @@ void cdrInterrupt(void) { cdr.LocL[0] = LOCL_INVALID; cdr.SubqForwardSectors = 1; cdr.sectorsRead = 0; + cdr.DriveState = DRIVESTATE_SEEK; cycles = (cdr.Mode & MODE_SPEED) ? cdReadTime : cdReadTime * 2; cycles += seekTime; @@ -1261,44 +1309,6 @@ static void cdrPrepCdda(s16 *buf, int samples) #endif } -static void cdrAttenuate(s16 *buf, int samples, int stereo) -{ - int i, l, r; - int ll = cdr.AttenuatorLeftToLeft; - int lr = cdr.AttenuatorLeftToRight; - int rl = cdr.AttenuatorRightToLeft; - int rr = cdr.AttenuatorRightToRight; - - if (lr == 0 && rl == 0 && 0x78 <= ll && ll <= 0x88 && 0x78 <= rr && rr <= 0x88) - return; - - if (!stereo && ll == 0x40 && lr == 0x40 && rl == 0x40 && rr == 0x40) - return; - - if (stereo) { - for (i = 0; i < samples; i++) { - l = buf[i * 2]; - r = buf[i * 2 + 1]; - l = (l * ll + r * rl) >> 7; - r = (r * rr + l * lr) >> 7; - ssat32_to_16(l); - ssat32_to_16(r); - buf[i * 2] = l; - buf[i * 2 + 1] = r; - } - } - else { - for (i = 0; i < samples; i++) { - l = buf[i]; - l = l * (ll + rl) >> 7; - //r = r * (rr + lr) >> 7; - ssat32_to_16(l); - //ssat32_to_16(r); - buf[i] = l; - } - } -} - static void cdrReadInterruptSetResult(unsigned char result) { if (cdr.IrqStat) { @@ -1332,6 +1342,7 @@ static void cdrReadInterrupt(void) int deliver_data = 1; u8 subqPos[3]; int read_ok; + int is_start; memcpy(subqPos, cdr.SetSectorPlay, sizeof(subqPos)); msfiAdd(subqPos, cdr.SubqForwardSectors); @@ -1344,6 +1355,7 @@ static void cdrReadInterrupt(void) // note: CdlGetlocL should work as soon as STATUS_READ is indicated SetPlaySeekRead(cdr.StatP, STATUS_READ | STATUS_ROTATING); + cdr.DriveState = DRIVESTATE_PLAY_READ; cdr.sectorsRead++; read_ok = ReadTrack(cdr.SetSectorPlay); @@ -1355,6 +1367,7 @@ static void cdrReadInterrupt(void) if (!read_ok) { CDR_LOG_I("cdrReadInterrupt() Log: err\n"); cdrReadInterruptSetResult(cdr.StatP | STATUS_ERROR); + cdr.DriveState = DRIVESTATE_PAUSED; // ? return; } memcpy(cdr.LocL, buf, 8); @@ -1391,12 +1404,10 @@ static void cdrReadInterrupt(void) if (Config.Xa) break; - if (!cdr.Muted && cdr.AdpcmActive) { - cdrAttenuate(cdr.Xa.pcm, cdr.Xa.nsamples, cdr.Xa.stereo); - SPU_playADPCMchannel(&cdr.Xa, psxRegs.cycle, 0); - } - // decode next - cdr.AdpcmActive = !xa_decode_sector(&cdr.Xa, buf + 4, !cdr.AdpcmActive); + is_start = !cdr.AdpcmActive; + cdr.AdpcmActive = !xa_decode_sector(&cdr.Xa, buf + 4, is_start); + if (cdr.AdpcmActive) + SPU_playADPCMchannel(&cdr.Xa, psxRegs.cycle, is_start); } while (0); if ((cdr.Mode & MODE_SF) && (subhdr->mode & 0x44) == 0x44) // according to nocash @@ -1441,7 +1452,7 @@ unsigned char cdrRead0(void) { } void cdrWrite0(unsigned char rt) { - CDR_LOG_IO("cdr w0.idx: %02x\n", rt); + CDR_LOG_IO("cdr w0.x.idx: %02x\n", rt); cdr.Ctrl = (rt & 3) | (cdr.Ctrl & ~3); } @@ -1455,13 +1466,13 @@ unsigned char cdrRead1(void) { if (cdr.ResultP == cdr.ResultC) cdr.ResultReady = 0; - CDR_LOG_IO("cdr r1.rsp: %02x #%u\n", psxHu8(0x1801), cdr.ResultP - 1); + CDR_LOG_IO("cdr r1.x.rsp: %02x #%u\n", psxHu8(0x1801), cdr.ResultP - 1); return psxHu8(0x1801); } void cdrWrite1(unsigned char rt) { - const char *rnames[] = { "cmd", "smd", "smc", "arr" }; (void)rnames; + const char *rnames[] = { "0.cmd", "1.smd", "2.smc", "3.arr" }; (void)rnames; CDR_LOG_IO("cdr w1.%s: %02x\n", rnames[cdr.Ctrl & 3], rt); switch (cdr.Ctrl & 3) { @@ -1481,10 +1492,9 @@ void cdrWrite1(unsigned char rt) { SysPrintf(" Param[%d] = {", cdr.ParamC); for (i = 0; i < cdr.ParamC; i++) SysPrintf(" %x,", cdr.Param[i]); - SysPrintf("}\n"); - } else { - SysPrintf("\n"); + SysPrintf("}"); } + SysPrintf(" @%08x\n", psxRegs.pc); #endif cdr.ResultReady = 0; @@ -1513,12 +1523,12 @@ unsigned char cdrRead2(void) { else CDR_LOG_I("read empty fifo (%d)\n", cdr.FifoSize); - CDR_LOG_IO("cdr r2.dat: %02x\n", ret); + CDR_LOG_IO("cdr r2.x.dat: %02x\n", ret); return ret; } void cdrWrite2(unsigned char rt) { - const char *rnames[] = { "prm", "ien", "all", "arl" }; (void)rnames; + const char *rnames[] = { "0.prm", "1.ien", "2.all", "3.arl" }; (void)rnames; CDR_LOG_IO("cdr w2.%s: %02x\n", rnames[cdr.Ctrl & 3], rt); switch (cdr.Ctrl & 3) { @@ -1545,12 +1555,14 @@ unsigned char cdrRead3(void) { else psxHu8(0x1803) = cdr.IrqMask | 0xE0; - CDR_LOG_IO("cdr r3.%s: %02x\n", (cdr.Ctrl & 1) ? "ifl" : "ien", psxHu8(0x1803)); + CDR_LOG_IO("cdr r3.%d.%s: %02x\n", cdr.Ctrl & 3, + (cdr.Ctrl & 1) ? "ifl" : "ien", psxHu8(0x1803)); return psxHu8(0x1803); } void cdrWrite3(unsigned char rt) { - const char *rnames[] = { "req", "ifl", "alr", "ava" }; (void)rnames; + const char *rnames[] = { "0.req", "1.ifl", "2.alr", "3.ava" }; (void)rnames; + u8 ll, lr, rl, rr; CDR_LOG_IO("cdr w3.%s: %02x\n", rnames[cdr.Ctrl & 3], rt); switch (cdr.Ctrl & 3) { @@ -1586,11 +1598,20 @@ void cdrWrite3(unsigned char rt) { cdr.AttenuatorLeftToRightT = rt; return; case 3: + if (rt & 0x01) + log_unhandled("Mute ADPCM?\n"); if (rt & 0x20) { - memcpy(&cdr.AttenuatorLeftToLeft, &cdr.AttenuatorLeftToLeftT, 4); - CDR_LOG("CD-XA Volume: %02x %02x | %02x %02x\n", - cdr.AttenuatorLeftToLeft, cdr.AttenuatorLeftToRight, - cdr.AttenuatorRightToLeft, cdr.AttenuatorRightToRight); + ll = cdr.AttenuatorLeftToLeftT; lr = cdr.AttenuatorLeftToRightT; + rl = cdr.AttenuatorRightToLeftT; rr = cdr.AttenuatorRightToRightT; + if (ll == cdr.AttenuatorLeftToLeft && + lr == cdr.AttenuatorLeftToRight && + rl == cdr.AttenuatorRightToLeft && + rr == cdr.AttenuatorRightToRight) + return; + cdr.AttenuatorLeftToLeft = ll; cdr.AttenuatorLeftToRight = lr; + cdr.AttenuatorRightToLeft = rl; cdr.AttenuatorRightToRight = rr; + CDR_LOG_I("CD-XA Volume: %02x %02x | %02x %02x\n", ll, lr, rl, rr); + SPU_setCDvol(ll, lr, rl, rr, psxRegs.cycle); } return; } @@ -1634,6 +1655,7 @@ void psxDma3(u32 madr, u32 bcr, u32 chcr) { switch (chcr & 0x71000000) { case 0x11000000: + madr &= ~3; ptr = getDmaRam(madr, &max_words); if (ptr == INVALID_PTR) { CDR_LOG_I("psxDma3() Log: *** DMA 3 *** NULL Pointer!\n"); @@ -1713,28 +1735,14 @@ void cdrReset() { cdr.FilterChannel = 0; cdr.IrqMask = 0x1f; cdr.IrqStat = NoIntr; - cdr.FifoOffset = DATA_SIZE; // fifo empty - CDR_getStatus(&stat); - if (stat.Status & STATUS_SHELLOPEN) { - cdr.DriveState = DRIVESTATE_LID_OPEN; - cdr.StatP = STATUS_SHELLOPEN; - } - else if (CdromId[0] == '\0') { - cdr.DriveState = DRIVESTATE_STOPPED; - cdr.StatP = 0; - } - else { - cdr.DriveState = DRIVESTATE_STANDBY; - cdr.StatP = STATUS_ROTATING; - } - // BIOS player - default values cdr.AttenuatorLeftToLeft = 0x80; cdr.AttenuatorLeftToRight = 0x00; cdr.AttenuatorRightToLeft = 0x00; cdr.AttenuatorRightToRight = 0x80; + softReset(); getCdInfo(); } @@ -1756,6 +1764,7 @@ int cdrFreeze(void *f, int Mode) { gzfreeze(&tmp, sizeof(tmp)); if (Mode == 0) { + u8 ll = 0, lr = 0, rl = 0, rr = 0; getCdInfo(); cdr.FifoOffset = tmp < DATA_SIZE ? tmp : DATA_SIZE; @@ -1778,6 +1787,10 @@ int cdrFreeze(void *f, int Mode) { if (!Config.Cdda) CDR_play(cdr.SetSectorPlay); } + if (!cdr.Muted) + ll = cdr.AttenuatorLeftToLeft, lr = cdr.AttenuatorLeftToLeft, + rl = cdr.AttenuatorRightToLeft, rr = cdr.AttenuatorRightToRight; + SPU_setCDvol(ll, lr, rl, rr, psxRegs.cycle); } return 0; diff --git a/pcsx_rearmed/libpcsxcore/cheat.c b/pcsx_rearmed/libpcsxcore/cheat.c index e0cf411e..2727fd23 100644 --- a/pcsx_rearmed/libpcsxcore/cheat.c +++ b/pcsx_rearmed/libpcsxcore/cheat.c @@ -20,6 +20,7 @@ #include "r3000a.h" #include "psxmem.h" #include "misc.h" +#include "../frontend/plugin_lib.h" // in_keystate for D4 #include "cheat.h" @@ -228,6 +229,10 @@ void ApplyCheats() { psxMu16ref(addr) = SWAPu16(val); break; + case CHEAT_SCRATCHPAD16: // 1F + psxHs16ref(addr) = SWAPu16(val); + break; + case CHEAT_INC16: psxMu16ref(addr) = SWAPu16(psxMu16(addr) + val); break; @@ -319,6 +324,20 @@ void ApplyCheats() { if (PSXMu16(addr) <= val) j++; // skip the next code break; + + case CHEAT_BUTTONS1_16: { // D4 + u16 keys = in_keystate[0]; + keys = (keys << 8) | (keys >> 8); + if (keys != val) + j++; // skip the next code + break; + } + + default: + SysPrintf("unhandled cheat %d,%d code %08X\n", + i, j, CheatCodes[j].Addr); + Cheats[i].WasEnabled = Cheats[i].Enabled = 0; + break; } } } @@ -350,7 +369,7 @@ int AddCheat(const char *descr, char *code) { p2 = code; while (c) { - unsigned int t1, t2; + unsigned int t1, t2, r; while (*p2 != '\n' && *p2 != '\0') p2++; @@ -363,9 +382,11 @@ int AddCheat(const char *descr, char *code) { t1 = 0; t2 = 0; - sscanf(p1, "%x %x", &t1, &t2); + r = sscanf(p1, "%x %x", &t1, &t2); - if (t1 > 0x10000000) { + if (r != 2) + SysPrintf("cheat %d: couldn't parse '%s'\n", NumCodes, p1); + else if (t1 >= 0x10000000) { if (NumCodes >= NumCodesAllocated) { NumCodesAllocated += ALLOC_INCREMENT; diff --git a/pcsx_rearmed/libpcsxcore/cheat.h b/pcsx_rearmed/libpcsxcore/cheat.h index b3d8bc4a..d8c2c66f 100644 --- a/pcsx_rearmed/libpcsxcore/cheat.h +++ b/pcsx_rearmed/libpcsxcore/cheat.h @@ -98,23 +98,27 @@ extern int NumCodesAllocated; #define PrevMu32(mem) (SWAP32(*(u32 *)PREVM(mem))) // cheat types -#define CHEAT_CONST8 0x30 /* 8-bit Constant Write */ -#define CHEAT_CONST16 0x80 /* 16-bit Constant Write */ -#define CHEAT_INC16 0x10 /* 16-bit Increment */ -#define CHEAT_DEC16 0x11 /* 16-bit Decrement */ -#define CHEAT_INC8 0x20 /* 8-bit Increment */ -#define CHEAT_DEC8 0x21 /* 8-bit Decrement */ -#define CHEAT_SLIDE 0x50 /* Slide Codes */ -#define CHEAT_MEMCPY 0xC2 /* Memory Copy */ - -#define CHEAT_EQU8 0xE0 /* 8-bit Equal To */ -#define CHEAT_NOTEQU8 0xE1 /* 8-bit Not Equal To */ -#define CHEAT_LESSTHAN8 0xE2 /* 8-bit Less Than */ -#define CHEAT_GREATERTHAN8 0xE3 /* 8-bit Greater Than */ -#define CHEAT_EQU16 0xD0 /* 16-bit Equal To */ -#define CHEAT_NOTEQU16 0xD1 /* 16-bit Not Equal To */ -#define CHEAT_LESSTHAN16 0xD2 /* 16-bit Less Than */ +#define CHEAT_CONST8 0x30 /* 8-bit Constant Write */ +#define CHEAT_CONST16 0x80 /* 16-bit Constant Write */ + +#define CHEAT_INC16 0x10 /* 16-bit Increment */ +#define CHEAT_DEC16 0x11 /* 16-bit Decrement */ +#define CHEAT_SCRATCHPAD16 0x1F /* 16-bit Scratchpad Write */ +#define CHEAT_INC8 0x20 /* 8-bit Increment */ +#define CHEAT_DEC8 0x21 /* 8-bit Decrement */ +#define CHEAT_SLIDE 0x50 /* Slide Codes */ +#define CHEAT_MEMCPY 0xC2 /* Memory Copy */ + +// conditionals +#define CHEAT_EQU16 0xD0 /* 16-bit Equal To */ +#define CHEAT_NOTEQU16 0xD1 /* 16-bit Not Equal To */ +#define CHEAT_LESSTHAN16 0xD2 /* 16-bit Less Than */ #define CHEAT_GREATERTHAN16 0xD3 /* 16-bit Greater Than */ +#define CHEAT_BUTTONS1_16 0xD4 /* button presses equate to YYYY */ +#define CHEAT_EQU8 0xE0 /* 8-bit Equal To */ +#define CHEAT_NOTEQU8 0xE1 /* 8-bit Not Equal To */ +#define CHEAT_LESSTHAN8 0xE2 /* 8-bit Less Than */ +#define CHEAT_GREATERTHAN8 0xE3 /* 8-bit Greater Than */ #ifdef __cplusplus } diff --git a/pcsx_rearmed/libpcsxcore/database.c b/pcsx_rearmed/libpcsxcore/database.c index 5cdd78b8..4872202d 100644 --- a/pcsx_rearmed/libpcsxcore/database.c +++ b/pcsx_rearmed/libpcsxcore/database.c @@ -33,18 +33,18 @@ static const char * const gpu_slow_llist_db[] = "SCES02834", "SCUS94570", "SCUS94616", "SCUS94654", /* Final Fantasy IV */ "SCES03840", "SLPM86028", "SLUS01360", + /* Point Blank - calibration cursor */ + "SCED00287", "SCES00886", "SLUS00481", + /* Simple 1500 Series Vol. 57: The Meiro */ + "SLPM86715", /* Spot Goes to Hollywood */ "SLES00330", "SLPS00394", "SLUS00014", + /* Tiny Tank */ + "SCES01338", "SCES02072", "SCES02072", "SCES02072", "SCES02072", "SCUS94427", /* Vampire Hunter D */ "SLES02731", "SLPS02477", "SLPS03198", "SLUS01138", }; -static const char * const gpu_busy_hack_db[] = -{ - /* ToHeart (Japan) */ - "SLPS01919", "SLPS01920", -}; - static const char * const gpu_centering_hack_db[] = { /* Gradius Gaiden */ @@ -53,6 +53,18 @@ static const char * const gpu_centering_hack_db[] = "SLPM86009", }; +static const char * const dualshock_timing1024_hack_db[] = +{ + /* Judge Dredd - could also be poor cdrom+mdec+dma timing */ + "SLUS00630", "SLES00755", +}; + +static const char * const dualshock_init_analog_hack_db[] = +{ + /* Formula 1 Championship Edition */ + "SLUS00546", +}; + #define HACK_ENTRY(var, list) \ { #var, &Config.hacks.var, list, ARRAY_SIZE(list) } @@ -67,46 +79,43 @@ hack_db[] = { HACK_ENTRY(cdr_read_timing, cdr_read_hack_db), HACK_ENTRY(gpu_slow_list_walking, gpu_slow_llist_db), - HACK_ENTRY(gpu_busy, gpu_busy_hack_db), HACK_ENTRY(gpu_centering, gpu_centering_hack_db), + HACK_ENTRY(gpu_timing1024, dualshock_timing1024_hack_db), + HACK_ENTRY(dualshock_init_analog, dualshock_init_analog_hack_db), }; static const struct { - const char * const id; int mult; + const char * const id[4]; } cycle_multiplier_overrides[] = { /* note: values are = (10000 / gui_option) */ /* Internal Section - fussy about timings */ - { "SLPS01868", 202 }, + { 202, { "SLPS01868" } }, /* Super Robot Taisen Alpha - on the edge with 175, * changing memcard settings is enough to break/unbreak it */ - { "SLPS02528", 190 }, - { "SLPS02636", 190 }, + { 190, { "SLPS02528", "SLPS02636" } }, /* Brave Fencer Musashi - cd sectors arrive too fast */ - { "SLUS00726", 170 }, - { "SLPS01490", 170 }, + { 170, { "SLUS00726", "SLPS01490" } }, #if defined(DRC_DISABLE) || defined(LIGHTREC) /* new_dynarec has a hack for this game */ /* Parasite Eve II - internal timer checks */ - { "SLUS01042", 125 }, - { "SLUS01055", 125 }, - { "SLES02558", 125 }, - { "SLES12558", 125 }, + { 125, { "SLUS01042", "SLUS01055", "SLES02558", "SLES12558" } }, #endif /* Discworld Noir - audio skips if CPU runs too fast */ - { "SLES01549", 222 }, - { "SLES02063", 222 }, - { "SLES02064", 222 }, - /* Judge Dredd - could also be poor MDEC timing */ - { "SLUS00630", 128 }, - { "SLES00755", 128 }, + { 222, { "SLES01549", "SLES02063", "SLES02064" } }, /* Digimon World */ - { "SLUS01032", 153 }, - { "SLES02914", 153 }, + { 153, { "SLUS01032", "SLES02914" } }, /* Syphon Filter - reportedly hangs under unknown conditions */ - { "SCUS94240", 169 }, + { 169, { "SCUS94240" } }, + /* Psychic Detective - some weird race condition in the game's cdrom code */ + { 222, { "SLUS00165", "SLUS00166", "SLUS00167" } }, + { 222, { "SLES00070", "SLES10070", "SLES20070" } }, + /* Vib-Ribbon - cd timing issues (PAL+ari64drc only?) */ + { 200, { "SCES02873" } }, + /* Zero Divide - sometimes too fast */ + { 200, { "SLUS00183", "SLES00159", "SLPS00083", "SLPM80008" } }, }; static const struct @@ -157,6 +166,12 @@ void Apply_Hacks_Cdrom(void) } } + if (Config.hacks.dualshock_init_analog) { + // assume the default is off, see LoadPAD1plugin() + for (i = 0; i < 8; i++) + padToggleAnalog(i); + } + /* Apply Memory card hack for Codename Tenka. (The game needs one of the memory card slots to be empty) */ for (i = 0; i < ARRAY_SIZE(MemorycardHack_db); i++) { @@ -176,7 +191,11 @@ void Apply_Hacks_Cdrom(void) for (i = 0; i < ARRAY_SIZE(cycle_multiplier_overrides); i++) { - if (strcmp(CdromId, cycle_multiplier_overrides[i].id) == 0) + const char * const * const ids = cycle_multiplier_overrides[i].id; + for (j = 0; j < ARRAY_SIZE(cycle_multiplier_overrides[i].id); j++) + if (ids[j] && strcmp(ids[j], CdromId) == 0) + break; + if (j < ARRAY_SIZE(cycle_multiplier_overrides[i].id)) { Config.cycle_multiplier_override = cycle_multiplier_overrides[i].mult; new_dynarec_hacks_pergame |= NDHACK_OVERRIDE_CYCLE_M; diff --git a/pcsx_rearmed/libpcsxcore/decode_xa.h b/pcsx_rearmed/libpcsxcore/decode_xa.h index 54065356..2d85c931 100644 --- a/pcsx_rearmed/libpcsxcore/decode_xa.h +++ b/pcsx_rearmed/libpcsxcore/decode_xa.h @@ -30,7 +30,7 @@ typedef struct { s32 y0, y1; } ADPCM_Decode_t; -typedef struct { +typedef struct xa_decode { int freq; int nbits; int stereo; diff --git a/pcsx_rearmed/libpcsxcore/lightrec/plugin.c b/pcsx_rearmed/libpcsxcore/lightrec/plugin.c index 22342fef..27fdc476 100644 --- a/pcsx_rearmed/libpcsxcore/lightrec/plugin.c +++ b/pcsx_rearmed/libpcsxcore/lightrec/plugin.c @@ -335,6 +335,14 @@ static void lightrec_enable_ram(struct lightrec_state *state, bool enable) static bool lightrec_can_hw_direct(u32 kaddr, bool is_write, u8 size) { + if (is_write && size != 32) { + // force32 so must go through handlers + if (0x1f801000 <= kaddr && kaddr < 0x1f801024) + return false; + if ((kaddr & 0x1fffff80) == 0x1f801080) // dma + return false; + } + switch (size) { case 8: switch (kaddr) { @@ -563,7 +571,8 @@ static void lightrec_plugin_execute_block(enum blockExecCaller caller) static void lightrec_plugin_clear(u32 addr, u32 size) { - if (addr == 0 && size == UINT32_MAX) + if ((addr == 0 && size == UINT32_MAX) + || (lightrec_hacks & LIGHTREC_OPT_INV_DMA_ONLY)) lightrec_invalidate_all(lightrec_state); else /* size * 4: PCSX uses DMA units */ diff --git a/pcsx_rearmed/libpcsxcore/mdec.c b/pcsx_rearmed/libpcsxcore/mdec.c index c0f2cfd7..38b03e1b 100644 --- a/pcsx_rearmed/libpcsxcore/mdec.c +++ b/pcsx_rearmed/libpcsxcore/mdec.c @@ -227,8 +227,8 @@ struct _pending_dma1 { static struct { u32 reg0; u32 reg1; - u16 * rl; - u16 * rl_end; + const u16 * rl; + const u16 * rl_end; u8 * block_buffer_pos; u8 block_buffer[16*16*3]; struct _pending_dma1 pending_dma1; @@ -258,7 +258,7 @@ static int aanscales[DSIZE2] = { 289301, 401273, 377991, 340183, 289301, 227303, 156569, 79818 }; -static void iqtab_init(int *iqtab, unsigned char *iq_y) { +static void iqtab_init(int *iqtab, const unsigned char *iq_y) { int i; for (i = 0; i < DSIZE2; i++) { @@ -268,7 +268,7 @@ static void iqtab_init(int *iqtab, unsigned char *iq_y) { #define MDEC_END_OF_DATA 0xfe00 -static unsigned short *rl2blk(int *blk, unsigned short *mdec_rl) { +static const unsigned short *rl2blk(int *blk, const unsigned short *mdec_rl) { int i, k, q_scale, rl, used_col; int *iqtab; @@ -472,7 +472,8 @@ u32 mdecRead1(void) { } void psxDma0(u32 adr, u32 bcr, u32 chcr) { - int cmd = mdec.reg0; + u32 cmd = mdec.reg0, words_max = 0; + const void *mem; int size; if (chcr != 0x01000201) { @@ -485,9 +486,17 @@ void psxDma0(u32 adr, u32 bcr, u32 chcr) { size = (bcr >> 16) * (bcr & 0xffff); + adr &= ~3; + mem = getDmaRam(adr, &words_max); + if (mem == INVALID_PTR || size > words_max) { + log_unhandled("bad dma0 madr %x\n", adr); + HW_DMA0_CHCR &= SWAP32(~0x01000000); + return; + } + switch (cmd >> 28) { case 0x3: // decode 15/24bpp - mdec.rl = (u16 *) PSXM(adr); + mdec.rl = mem; /* now the mdec is busy till all data are decoded */ mdec.reg1 |= MDEC1_BUSY; /* detect the end of decoding */ @@ -507,7 +516,7 @@ void psxDma0(u32 adr, u32 bcr, u32 chcr) { case 0x4: // quantization table upload { - u8 *p = (u8 *)PSXM(adr); + const u8 *p = mem; // printf("uploading new quantization table\n"); // printmatrixu8(p); // printmatrixu8(p + 64); @@ -541,10 +550,10 @@ void mdec0Interrupt() #define SIZE_OF_16B_BLOCK (16*16*2) void psxDma1(u32 adr, u32 bcr, u32 chcr) { + u32 words, words_max = 0; int blk[DSIZE2 * 6]; u8 * image; int size; - u32 words; if (chcr != 0x01000200) { log_unhandled("mdec1: invalid dma %08x\n", chcr); @@ -561,9 +570,16 @@ void psxDma1(u32 adr, u32 bcr, u32 chcr) { mdec.pending_dma1.bcr = bcr; mdec.pending_dma1.chcr = chcr; /* do not free the dma */ - } else { + return; + } - image = (u8 *)PSXM(adr); + adr &= ~3; + image = getDmaRam(adr, &words_max); + if (image == INVALID_PTR || words > words_max) { + log_unhandled("bad dma1 madr %x\n", adr); + HW_DMA1_CHCR &= SWAP32(~0x01000000); + return; + } if (mdec.reg0 & MDEC0_RGB24) { /* 16 bits decoding @@ -623,12 +639,13 @@ void psxDma1(u32 adr, u32 bcr, u32 chcr) { mdec.block_buffer_pos = mdec.block_buffer + size; } } + if (size < 0) + log_unhandled("mdec: bork\n"); - /* define the power of mdec */ - set_event(PSXINT_MDECOUTDMA, words * MDEC_BIAS); - /* some CPU stalling */ - psxRegs.cycle += words; - } + /* define the power of mdec */ + set_event(PSXINT_MDECOUTDMA, words * MDEC_BIAS); + /* some CPU stalling */ + psxRegs.cycle += words; } void mdec1Interrupt() { @@ -657,6 +674,7 @@ void mdec1Interrupt() { */ /* MDEC_END_OF_DATA avoids read outside memory */ + //printf("mdec left %zd, v=%04x\n", mdec.rl_end - mdec.rl, *(mdec.rl)); if (mdec.rl >= mdec.rl_end || SWAP16(*(mdec.rl)) == MDEC_END_OF_DATA) { mdec.reg1 &= ~(MDEC1_STP|MDEC1_BUSY); if (HW_DMA0_CHCR & SWAP32(0x01000000)) diff --git a/pcsx_rearmed/libpcsxcore/misc.c b/pcsx_rearmed/libpcsxcore/misc.c index f175e2a3..0848c267 100644 --- a/pcsx_rearmed/libpcsxcore/misc.c +++ b/pcsx_rearmed/libpcsxcore/misc.c @@ -301,7 +301,7 @@ int LoadCdrom() { return 0; } -int LoadCdromFile(const char *filename, EXE_HEADER *head) { +int LoadCdromFile(const char *filename, EXE_HEADER *head, u8 *time_bcd_out) { struct iso_directory_record *dir; u8 time[4],*buf; u8 mdir[4096]; @@ -334,6 +334,7 @@ int LoadCdromFile(const char *filename, EXE_HEADER *head) { if (GetCdromFile(mdir, time, exename) == -1) return -1; READTRACK(); + incTime(); memcpy(head, buf + 12, sizeof(EXE_HEADER)); size = SWAP32(head->t_size); @@ -343,8 +344,8 @@ int LoadCdromFile(const char *filename, EXE_HEADER *head) { //psxCpu->Reset(); while (size & ~2047) { - incTime(); READTRACK(); + incTime(); mem = PSXM(addr); if (mem != INVALID_PTR) @@ -353,6 +354,8 @@ int LoadCdromFile(const char *filename, EXE_HEADER *head) { size -= 2048; addr += 2048; } + if (time_bcd_out) + memcpy(time_bcd_out, time, 3); return 0; } @@ -674,6 +677,10 @@ int SaveState(const char *file) { assert(!psxRegs.branching); assert(!psxRegs.cpuInRecursion); assert(!misc->magic); + + f = SaveFuncs.open(file, "wb"); + if (f == NULL) return -1; + misc->magic = MISC_MAGIC; misc->gteBusyCycle = psxRegs.gteBusyCycle; misc->muldivBusyCycle = psxRegs.muldivBusyCycle; @@ -684,9 +691,6 @@ int SaveState(const char *file) { misc->frame_counter = frame_counter; misc->CdromFrontendId = CdromFrontendId; - f = SaveFuncs.open(file, "wb"); - if (f == NULL) return -1; - psxCpu->Notify(R3000ACPU_NOTIFY_BEFORE_SAVE, NULL); SaveFuncs.write(f, (void *)PcsxHeader, 32); diff --git a/pcsx_rearmed/libpcsxcore/misc.h b/pcsx_rearmed/libpcsxcore/misc.h index 539acc7b..22245d88 100644 --- a/pcsx_rearmed/libpcsxcore/misc.h +++ b/pcsx_rearmed/libpcsxcore/misc.h @@ -60,7 +60,7 @@ extern int CdromFrontendId; // for frontend use int BiosBootBypass(); int LoadCdrom(); -int LoadCdromFile(const char *filename, EXE_HEADER *head); +int LoadCdromFile(const char *filename, EXE_HEADER *head, u8 *time_bcd_out); int CheckCdrom(); int Load(const char *ExePath); diff --git a/pcsx_rearmed/libpcsxcore/new_dynarec/new_dynarec.c b/pcsx_rearmed/libpcsxcore/new_dynarec/new_dynarec.c index 74f32ee3..d9438d88 100644 --- a/pcsx_rearmed/libpcsxcore/new_dynarec/new_dynarec.c +++ b/pcsx_rearmed/libpcsxcore/new_dynarec/new_dynarec.c @@ -23,6 +23,7 @@ #include #include #include +#include #ifdef __MACH__ #include #endif @@ -111,18 +112,16 @@ struct ndrc_mem struct ndrc_tramp tramp; }; -#ifdef BASE_ADDR_DYNAMIC static struct ndrc_mem *ndrc; -#else -static struct ndrc_mem ndrc_ __attribute__((aligned(4096))); -static struct ndrc_mem *ndrc = &ndrc_; +#ifndef BASE_ADDR_DYNAMIC +// reserve .bss space with upto 64k page size in mind +static char ndrc_bss[((sizeof(*ndrc) + 65535) & ~65535) + 65536]; #endif #ifdef TC_WRITE_OFFSET # ifdef __GLIBC__ # include # include # include -# include # endif static long ndrc_write_ofs; #define NDRC_WRITE_OFFSET(x) (void *)((char *)(x) + ndrc_write_ofs) @@ -6262,9 +6261,22 @@ void new_dynarec_clear_full(void) new_dynarec_hacks_old = new_dynarec_hacks; } +static int pgsize(void) +{ + long ret = -1; +#ifdef _SC_PAGESIZE + ret = sysconf(_SC_PAGESIZE); +#endif + if (ret < 1) + ret = 4096; + return ret; +} + void new_dynarec_init(void) { - SysPrintf("Init new dynarec, ndrc size %x\n", (int)sizeof(*ndrc)); + int align = pgsize() - 1; + SysPrintf("Init new dynarec, ndrc size %x, pgsize %d\n", + (int)sizeof(*ndrc), align + 1); #ifdef _3DS check_rosalina(); @@ -6320,11 +6332,12 @@ void new_dynarec_init(void) #endif #else #ifndef NO_WRITE_EXEC + ndrc = (struct ndrc_mem *)((size_t)(ndrc_bss + align) & ~align); // not all systems allow execute in data segment by default // size must be 4K aligned for 3DS? if (mprotect(ndrc, sizeof(*ndrc), PROT_READ | PROT_WRITE | PROT_EXEC) != 0) - SysPrintf("mprotect() failed: %s\n", strerror(errno)); + SysPrintf("mprotect(%p) failed: %s\n", ndrc, strerror(errno)); #endif #endif out = ndrc->translation_cache; diff --git a/pcsx_rearmed/libpcsxcore/new_dynarec/pcsxmem.c b/pcsx_rearmed/libpcsxcore/new_dynarec/pcsxmem.c index e61e8a35..905f3a2c 100644 --- a/pcsx_rearmed/libpcsxcore/new_dynarec/pcsxmem.c +++ b/pcsx_rearmed/libpcsxcore/new_dynarec/pcsxmem.c @@ -510,10 +510,6 @@ void new_dyna_pcsx_mem_reset(void) // plugins might change so update the pointers map_item(&mem_iortab[IOMEM32(0x1810)], GPU_readData, 1); map_item(&mem_iowtab[IOMEM32(0x1810)], GPU_writeData, 1); - if (Config.hacks.gpu_busy) - map_item(&mem_iortab[IOMEM32(0x1814)], psxHwReadGpuSRbusyHack, 1); - else - map_item(&mem_iortab[IOMEM32(0x1814)], psxHwReadGpuSR, 1); } void new_dyna_pcsx_mem_shutdown(void) diff --git a/pcsx_rearmed/libpcsxcore/plugins.c b/pcsx_rearmed/libpcsxcore/plugins.c index d44442b0..9a399823 100644 --- a/pcsx_rearmed/libpcsxcore/plugins.c +++ b/pcsx_rearmed/libpcsxcore/plugins.c @@ -31,9 +31,6 @@ static s64 cdOpenCaseTime = 0; GPUupdateLace GPU_updateLace; GPUinit GPU_init; GPUshutdown GPU_shutdown; -GPUconfigure GPU_configure; -GPUtest GPU_test; -GPUabout GPU_about; GPUopen GPU_open; GPUclose GPU_close; GPUreadStatus GPU_readStatus; @@ -86,6 +83,7 @@ SPUregisterCallback SPU_registerCallback; SPUregisterScheduleCb SPU_registerScheduleCb; SPUasync SPU_async; SPUplayCDDAchannel SPU_playCDDAchannel; +SPUsetCDvol SPU_setCDvol; PADconfigure PAD1_configure; PADabout PAD1_about; @@ -179,7 +177,7 @@ static const char *err; #define LoadSym(dest, src, name, checkerr) { \ dest = (src)SysLoadSym(drv, name); \ - if (checkerr) { CheckErr(name); } else SysLibError(); \ + if (checkerr) { CheckErr(name); } \ } void *hGPUDriver = NULL; @@ -213,7 +211,6 @@ static int LoadGPUplugin(const char *GPUdll) { hGPUDriver = SysLoadLibrary(GPUdll); if (hGPUDriver == NULL) { - GPU_configure = NULL; SysMessage (_("Could not load GPU plugin %s!"), GPUdll); return -1; } drv = hGPUDriver; @@ -237,9 +234,6 @@ static int LoadGPUplugin(const char *GPUdll) { LoadGpuSym0(showScreenPic, "GPUshowScreenPic"); LoadGpuSym0(vBlank, "GPUvBlank"); LoadGpuSym0(getScreenInfo, "GPUgetScreenInfo"); - LoadGpuSym0(configure, "GPUconfigure"); - LoadGpuSym0(test, "GPUtest"); - LoadGpuSym0(about, "GPUabout"); return 0; } @@ -313,13 +307,15 @@ static int LoadCDRplugin(const char *CDRdll) { static void *hSPUDriver = NULL; static void CALLBACK SPU__registerScheduleCb(void (CALLBACK *cb)(unsigned int)) {} +static void CALLBACK SPU__setCDvol(unsigned char ll, unsigned char lr, + unsigned char rl, unsigned char rr, unsigned int cycle) {} #define LoadSpuSym1(dest, name) \ LoadSym(SPU_##dest, SPU##dest, name, TRUE); #define LoadSpuSym0(dest, name) \ LoadSym(SPU_##dest, SPU##dest, name, FALSE); \ - if (SPU_##dest == NULL) SPU_##dest = (SPU##dest) SPU__##dest; + if (SPU_##dest == NULL) SPU_##dest = SPU__##dest; #define LoadSpuSymN(dest, name) \ LoadSym(SPU_##dest, SPU##dest, name, FALSE); @@ -346,6 +342,7 @@ static int LoadSPUplugin(const char *SPUdll) { LoadSpuSym0(registerScheduleCb, "SPUregisterScheduleCb"); LoadSpuSymN(async, "SPUasync"); LoadSpuSymN(playCDDAchannel, "SPUplayCDDAchannel"); + LoadSpuSym0(setCDvol, "SPUsetCDvol"); return 0; } @@ -490,16 +487,28 @@ static void initBufForRequest(int padIndex, char value) { return; } - // switch to analog mode automatically after the game finishes init - if (value == 0x42 && pads[padIndex].ds.padMode == 0) - pads[padIndex].ds.digitalModeFrames++; - if (pads[padIndex].ds.digitalModeFrames == 60*4) { - pads[padIndex].ds.padMode = 1; - pads[padIndex].ds.digitalModeFrames = 0; - } - - if ((u32)(frame_counter - pads[padIndex].ds.lastUseFrame) > 60u) + if ((u32)(frame_counter - pads[padIndex].ds.lastUseFrame) > 2*60u + && pads[padIndex].ds.configModeUsed + && !Config.hacks.dualshock_init_analog) + { + //SysPrintf("Pad reset\n"); pads[padIndex].ds.padMode = 0; // according to nocash + pads[padIndex].ds.autoAnalogTried = 0; + } + else if (pads[padIndex].ds.padMode == 0 && value == CMD_READ_DATA_AND_VIBRATE + && pads[padIndex].ds.configModeUsed + && !pads[padIndex].ds.configMode + && !pads[padIndex].ds.userToggled) + { + if (pads[padIndex].ds.autoAnalogTried == 16) { + // auto-enable for convenience + SysPrintf("Auto-enabling dualshock analog mode.\n"); + pads[padIndex].ds.padMode = 1; + pads[padIndex].ds.autoAnalogTried = 255; + } + else if (pads[padIndex].ds.autoAnalogTried < 16) + pads[padIndex].ds.autoAnalogTried++; + } pads[padIndex].ds.lastUseFrame = frame_counter; switch (value) { @@ -991,6 +1000,17 @@ int padFreeze(void *f, int Mode) { return 0; } +int padToggleAnalog(unsigned int index) +{ + int r = -1; + + if (index < sizeof(pads) / sizeof(pads[0])) { + r = (pads[index].ds.padMode ^= 1); + pads[index].ds.userToggled = 1; + } + return r; +} + void *hNETDriver = NULL; diff --git a/pcsx_rearmed/libpcsxcore/plugins.h b/pcsx_rearmed/libpcsxcore/plugins.h index 269ef18a..df8ed87d 100644 --- a/pcsx_rearmed/libpcsxcore/plugins.h +++ b/pcsx_rearmed/libpcsxcore/plugins.h @@ -58,11 +58,8 @@ typedef void (CALLBACK* GPUwriteDataMem)(uint32_t *, int); typedef uint32_t (CALLBACK* GPUreadStatus)(void); typedef uint32_t (CALLBACK* GPUreadData)(void); typedef void (CALLBACK* GPUreadDataMem)(uint32_t *, int); -typedef long (CALLBACK* GPUdmaChain)(uint32_t *,uint32_t, uint32_t *); +typedef long (CALLBACK* GPUdmaChain)(uint32_t *, uint32_t, uint32_t *, int32_t *); typedef void (CALLBACK* GPUupdateLace)(void); -typedef long (CALLBACK* GPUconfigure)(void); -typedef long (CALLBACK* GPUtest)(void); -typedef void (CALLBACK* GPUabout)(void); typedef void (CALLBACK* GPUmakeSnapshot)(void); typedef void (CALLBACK* GPUkeypressed)(int); typedef void (CALLBACK* GPUdisplayText)(char *); @@ -82,9 +79,6 @@ typedef void (CALLBACK* GPUgetScreenInfo)(int *, int *); extern GPUupdateLace GPU_updateLace; extern GPUinit GPU_init; extern GPUshutdown GPU_shutdown; -extern GPUconfigure GPU_configure; -extern GPUtest GPU_test; -extern GPUabout GPU_about; extern GPUopen GPU_open; extern GPUclose GPU_close; extern GPUreadStatus GPU_readStatus; @@ -179,7 +173,7 @@ typedef struct { uint32_t PluginVersion; uint32_t Size; } SPUFreezeHdr_t; -typedef struct { +typedef struct SPUFreeze { unsigned char PluginName[8]; uint32_t PluginVersion; uint32_t Size; @@ -188,9 +182,10 @@ typedef struct { xa_decode_t xa; unsigned char *unused; } SPUFreeze_t; -typedef long (CALLBACK* SPUfreeze)(uint32_t, SPUFreeze_t *, uint32_t); -typedef void (CALLBACK* SPUasync)(uint32_t, uint32_t); +typedef long (CALLBACK* SPUfreeze)(unsigned int, struct SPUFreeze *, unsigned int); +typedef void (CALLBACK* SPUasync)(unsigned int, unsigned int); typedef int (CALLBACK* SPUplayCDDAchannel)(short *, int, unsigned int, int); +typedef void (CALLBACK* SPUsetCDvol)(unsigned char, unsigned char, unsigned char, unsigned char, unsigned int); // SPU function pointers extern SPUinit SPU_init; @@ -207,6 +202,7 @@ extern SPUregisterCallback SPU_registerCallback; extern SPUregisterScheduleCb SPU_registerScheduleCb; extern SPUasync SPU_async; extern SPUplayCDDAchannel SPU_playCDDAchannel; +extern SPUsetCDvol SPU_setCDvol; // PAD Functions typedef long (CALLBACK* PADconfigure)(void); @@ -384,6 +380,7 @@ boolean UsingIso(void); void SetCdOpenCaseTime(s64 time); int padFreeze(void *f, int Mode); +int padToggleAnalog(unsigned int index); extern void pl_gun_byte2(int port, unsigned char byte); extern void plat_trigger_vibrate(int pad, int low, int high); diff --git a/pcsx_rearmed/libpcsxcore/psxbios.c b/pcsx_rearmed/libpcsxcore/psxbios.c index 3671af5a..1ecb63ec 100644 --- a/pcsx_rearmed/libpcsxcore/psxbios.c +++ b/pcsx_rearmed/libpcsxcore/psxbios.c @@ -37,12 +37,18 @@ #include "psxhle.h" #include "psxinterpreter.h" #include "psxevents.h" +#include "cdrom.h" +#include #include #ifndef PSXBIOS_LOG //#define PSXBIOS_LOG printf #define PSXBIOS_LOG(...) #endif +#ifndef PSXBIOS_EV_LOG +//#define PSXBIOS_EV_LOG printf +#define PSXBIOS_EV_LOG(...) +#endif #define PTR_1 (void *)(size_t)1 @@ -83,7 +89,7 @@ char *biosA0n[256] = { "dev_card_close", "dev_card_firstfile", "dev_card_nextfile","dev_card_erase", "dev_card_undelete","dev_card_format", "dev_card_rename", "dev_card_6f", // 0x70 - "_bu_init", "_96_init", "CdRemove", "sys_a0_73", + "_bu_init", "CdInit", "CdRemove", "sys_a0_73", "sys_a0_74", "sys_a0_75", "sys_a0_76", "sys_a0_77", "_96_CdSeekL", "sys_a0_79", "sys_a0_7a", "sys_a0_7b", "_96_CdGetStatus", "sys_a0_7d", "_96_CdRead", "sys_a0_7f", @@ -94,7 +100,7 @@ char *biosA0n[256] = { "sys_a0_8c", "sys_a0_8d", "sys_a0_8e", "sys_a0_8f", // 0x90 "sys_a0_90", "sys_a0_91", "sys_a0_92", "sys_a0_93", - "sys_a0_94", "sys_a0_95", "AddCDROMDevice", "AddMemCardDevide", + "sys_a0_94", "CdReset", "AddCDROMDevice", "AddMemCardDevide", "DisableKernelIORedirection", "EnableKernelIORedirection", "sys_a0_9a", "sys_a0_9b", "SetConf", "GetConf", "sys_a0_9e", "SetMem", // 0xa0 @@ -112,10 +118,10 @@ char *biosB0n[256] = { "SysMalloc", "sys_b0_01", "sys_b0_02", "sys_b0_03", "sys_b0_04", "sys_b0_05", "sys_b0_06", "DeliverEvent", "OpenEvent", "CloseEvent", "WaitEvent", "TestEvent", - "EnableEvent", "DisableEvent", "OpenTh", "CloseTh", + "EnableEvent", "DisableEvent", "OpenTh", "CloseTh", // 0x10 - "ChangeTh", "sys_b0_11", "InitPAD", "StartPAD", - "StopPAD", "PAD_init", "PAD_dr", "ReturnFromExecption", + "ChangeTh", "sys_b0_11", "InitPAD", "StartPAD", + "StopPAD", "PAD_init", "PAD_dr", "ReturnFromException", "ResetEntryInt", "HookEntryInt", "sys_b0_1a", "sys_b0_1b", "sys_b0_1c", "sys_b0_1d", "sys_b0_1e", "sys_b0_1f", // 0x20 @@ -272,6 +278,7 @@ static u32 floodchk; #define A_EXCEPTION 0x0c80 #define A_EXC_SP 0x6cf0 #define A_EEXIT_DEF 0x6cf4 +#define A_CARD_ISLOT 0x7264 // 0 or 1, toggled by card vint handler #define A_KMALLOC_PTR 0x7460 #define A_KMALLOC_SIZE 0x7464 #define A_KMALLOC_END 0x7468 @@ -283,7 +290,10 @@ static u32 floodchk; #define A_PAD_IN_LEN 0x74d8 #define A_PAD_OUT_LEN 0x74e0 #define A_PAD_DR_DST 0x74c4 -#define A_CARD_CHAN1 0x7500 +#define A_CARD_ACHAN 0x7500 // currently active port in 0xPortSlot format +#define A_CARD_HANDLER 0x7528 // ptr to irq handler +#define A_CARD_STATUS1 0x7568 +#define A_CARD_STATUS2 0x7569 #define A_PAD_DR_BUF1 0x7570 #define A_PAD_DR_BUF2 0x7598 #define A_EEXIT_PTR 0x75d0 @@ -303,10 +313,14 @@ static u32 floodchk; #define A_CD_EVENTS 0xb9b8 #define A_EXC_GP 0xf450 -#define A_A0_DUMMY 0x1010 -#define A_B0_DUMMY 0x2010 -#define A_C0_DUMMY 0x3010 -#define A_B0_5B_DUMMY 0x43d0 +#define A_A0_TRAPS 0x1010 +#define A_B0_TRAPS 0x2010 +#define A_C0_TRAPS 0x3010 +#define A_B0_5B_TRAP 0x43d0 + +#define CARD_HARDLER_WRITE 0x51F4 +#define CARD_HARDLER_READ 0x5688 +#define CARD_HARDLER_INFO 0x5B64 #define HLEOP(n) SWAPu32((0x3b << 26) | (n)); @@ -439,9 +453,10 @@ static inline void softCallInException(u32 pc) { ra = sra; } -static u32 OpenEvent(u32 class, u32 spec, u32 mode, u32 func); -static u32 DeliverEvent(u32 class, u32 spec); -static u32 UnDeliverEvent(u32 class, u32 spec); +static u32 OpenEvent(u32 class, u32 spec, u32 mode, u32 func); +static void EnableEvent(u32 ev, int do_log); +static u32 DeliverEvent(u32 class, u32 spec); +static u32 UnDeliverEvent(u32 class, u32 spec); static void CloseEvent(u32 ev); /* * @@ -532,12 +547,8 @@ void psxBios_putc(void) // 0x09, 0x3B pc0 = ra; } -void psxBios_todigit(void) // 0x0a +static u32 do_todigit(u32 c) { - int c = a0; -#ifdef PSXBIOS_LOG - PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x0a]); -#endif c &= 0xFF; if (c >= 0x30 && c < 0x3A) { c -= 0x30; @@ -549,14 +560,73 @@ void psxBios_todigit(void) // 0x0a c = c - 0x41 + 10; } else if (c >= 0x80) { + log_unhandled("todigit %02x\n", c); c = -1; } else { c = 0x0098967F; } - v0 = c; - pc0 = ra; + use_cycles(40); + return c; +} + +static void psxBios_todigit(void) // 0x0a +{ + mips_return(do_todigit(a0)); + PSXBIOS_LOG("psxBios_%s '%c' -> %u\n", biosA0n[0x0a], a0, v0); +} + +static void do_strtol(char *p, void *end_, u32 base, int can_neg) { + s32 n = 0, f = 0, t; + u32 *end = end_; + + use_cycles(12); + if (p == INVALID_PTR) { + mips_return(0); + return; + } + + for (; (0x09 <= *p && *p <= '\r') || *p == ' '; p++) + use_cycles(9); + if (can_neg) { + for (; *p == '-'; f = 1, p++) + use_cycles(4); + } + if (base == 0 || base > 36) + base = 10; + if (*p == '0') { + switch (*p++) { + case 'b': case 'B': base = 2; break; + case 'x': case 'X': base = 16; break; + } + } + else if (*p == 'o' || *p == 'O') { + base = 8; + p++; + } + + for (; (t = do_todigit(*p)) < base; p++) { + n = n * base + t; + use_cycles(12); + } + + n = (f ? -n : n); + if (end != INVALID_PTR) + *end = SWAP32(a0 + (p - Ra0)); + mips_return_c(n, 100); +} + +static void psxBios_strtoul() { // 0x0c + do_strtol(a0 ? Ra0 : INVALID_PTR, a1 ? Ra1 : INVALID_PTR, a2, 0); + PSXBIOS_LOG("psxBios_%s %s (%x), %x, %x -> 0x%x\n", + biosA0n[0x0c], a0 ? Ra0 : NULL, a0, a1, a2, v0); +} + +static void psxBios_strtol() { // 0x0d + do_strtol(a0 ? Ra0 : INVALID_PTR, a1 ? Ra1 : INVALID_PTR, a2, 1); + PSXBIOS_LOG("psxBios_%s %s (%x), %x, %x -> 0x%x\n", + biosA0n[0x0d], a0 ? Ra0 : NULL, a0, a1, a2, v0); } void psxBios_abs() { // 0x0e @@ -1528,11 +1598,53 @@ static void FlushCache() { use_cycles(500); } +// you likely want to mask irqs before calling these +static u8 cdrom_sync(int do_ack) +{ + u8 r = 0; + if (psxRegs.interrupt & (1u << PSXINT_CDR)) { + if ((s32)(psxRegs.cycle - event_cycles[PSXINT_CDR]) < 0) + psxRegs.cycle = event_cycles[PSXINT_CDR] + 1; + irq_test(&psxRegs.CP0); + } + if (do_ack) { + cdrWrite0(1); + r = cdrRead3() & 0x1f; + cdrWrite3(0x5f); // ack; clear params + } + return r; +} + +static void cdrom_cmd_and_wait(u8 cmd, int arg_cnt, int resp_cnt, ...) +{ + va_list ap; + + cdrom_sync(0); + cdrWrite0(0); + va_start(ap, resp_cnt); + while (arg_cnt-- > 0) + cdrWrite2(va_arg(ap, u32)); + va_end(ap); + cdrWrite1(cmd); + + if (resp_cnt > 0) { + u8 r = cdrom_sync(1); + assert(r == 3); (void)r; + cdrRead1(); + } + if (resp_cnt > 1) { + u8 r = cdrom_sync(1); + assert(r == 2); (void)r; + cdrRead1(); + } +} + /* * long Load(char *name, struct EXEC *header); */ void psxBios_Load() { // 0x42 + u8 time[3] = { 2, 0, 0x16 }; EXE_HEADER eheader; char path[256]; char *pa0, *p; @@ -1554,7 +1666,7 @@ void psxBios_Load() { // 0x42 else snprintf(path, sizeof(path), "%s", (char *)pa0); - if (LoadCdromFile(path, &eheader) == 0) { + if (LoadCdromFile(path, &eheader, time) == 0) { memcpy(pa1, ((char*)&eheader)+16, sizeof(EXEC)); psxCpu->Clear(a1, sizeof(EXEC) / 4); FlushCache(); @@ -1563,6 +1675,17 @@ void psxBios_Load() { // 0x42 PSXBIOS_LOG(" -> %d\n", v0); pc0 = ra; + + // set the cdrom to a state of just after exe read + psxRegs.CP0.n.SR &= ~0x404; + cdrom_sync(1); + cdrWrite0(1); + cdrWrite2(0x1f); // unmask + cdrom_cmd_and_wait(0x0e, 1, 1, 0x80u); // CdlSetmode + cdrom_cmd_and_wait(0x02, 3, 1, time[0], time[1], time[2]); // CdlSetloc + cdrom_cmd_and_wait(0x15, 0, 2); // CdlSeekL + psxHwWrite16(0x1f801070, ~4); + MTC0(&psxRegs, 12, psxRegs.CP0.n.SR | 0x404); } /* @@ -1631,6 +1754,14 @@ void psxBios_GPU_dw() { // 0x46 pc0 = ra; } +static void gpu_sync() { + // not implemented... + // might be problematic to do because of Config.GpuListWalking + if (psxRegs.interrupt & (1u << PSXINT_GPUDMA)) + log_unhandled("gpu_sync with active dma\n"); + mips_return_c(0, 21); +} + void psxBios_mem2vram() { // 0x47 int size; gpuSyncPluginSR(); // flush @@ -1657,8 +1788,8 @@ void psxBios_SendGPU() { // 0x48 void psxBios_GPU_cw() { // 0x49 GPU_writeData(a0); gpuSyncPluginSR(); - v0 = HW_GPU_STATUS; - pc0 = ra; + use_cycles(13); + gpu_sync(); } void psxBios_GPU_cwb() { // 0x4a @@ -1719,10 +1850,8 @@ void psxBios_LoadExec() { // 51 psxBios_Exec(); } -void psxBios__bu_init() { // 70 -#ifdef PSXBIOS_LOG +static void psxBios__bu_init() { // 70 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x70]); -#endif DeliverEvent(0xf0000011, 0x0004); DeliverEvent(0xf4000001, 0x0004); @@ -1730,24 +1859,86 @@ void psxBios__bu_init() { // 70 pc0 = ra; } -void psxBios__96_init() { // 71 -#ifdef PSXBIOS_LOG - PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x71]); -#endif - - pc0 = ra; -} - static void write_chain(u32 *d, u32 next, u32 handler1, u32 handler2); static void psxBios_SysEnqIntRP_(u32 priority, u32 chain_eptr); static void psxBios_SysDeqIntRP_(u32 priority, u32 chain_rm_eptr); +static void psxBios_EnqueueCdIntr_(void) +{ + u32 *ram32 = (u32 *)psxM; + + // traps should already be installed by write_chain() + ram32[0x91d0/4] = 0; + ram32[0x91d4/4] = SWAP32(0xbfc0506c); + ram32[0x91d8/4] = SWAP32(0xbfc04dec); + psxBios_SysEnqIntRP_(0, 0x91d0); + ram32[0x91e0/4] = 0; + ram32[0x91e4/4] = SWAP32(0xbfc050a4); + ram32[0x91e8/4] = SWAP32(0xbfc04fbc); + psxBios_SysEnqIntRP_(0, 0x91e0); + use_cycles(31); +} + +static void setup_cd_irq_and_events(void) +{ + u16 specs[] = { 0x10, 0x20, 0x40, 0x80, 0x8000 }; + size_t i; + + psxBios_EnqueueCdIntr_(); + + for (i = 0; i < sizeof(specs) / sizeof(specs[0]); i++) { + u32 h = OpenEvent(0xf0000003, specs[i], EvMdMARK, 0); + // no error checks + storeRam32(A_CD_EVENTS + i * 4, h); + EnableEvent(h, 0); + } +} + +static void psxBios_CdReset_() { + psxRegs.CP0.n.SR &= ~0x404; // disable interrupts + + cdrom_sync(1); + cdrWrite0(1); + cdrWrite2(0x1f); // unmask + cdrom_cmd_and_wait(0x0a, 0, 2); // CdlReset + cdrom_cmd_and_wait(0x0e, 1, 1, 0x80u); // CdlSetmode + + // todo(?): should read something (iso root directory?) + // from { 0, 2, 16 } to somewhere and pause + + mips_return(1); + psxHwWrite16(0x1f801070, ~4); + MTC0(&psxRegs, 12, psxRegs.CP0.n.SR | 0x404); + DeliverEvent(0xf0000003, 0x0020); +} + +static void psxBios_CdInit() { // 54, 71 + PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x71]); + setup_cd_irq_and_events(); + + psxBios_CdReset_(); + + // this function takes pretty much forever + mips_return_c(0, 50000*11); +} + static void psxBios_DequeueCdIntr_() { psxBios_SysDeqIntRP_(0, 0x91d0); psxBios_SysDeqIntRP_(0, 0x91e0); use_cycles(16); } +static void psxBios_CdReset() { // 95 + PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x95]); + psxBios_CdReset_(); +} + +static void psxBios_EnqueueCdIntr() { // a2 + PSXBIOS_LOG("psxBios_%s\n", biosA0n[0xa2]); + psxBios_EnqueueCdIntr_(); + // return value comes from SysEnqIntRP() insternal call +} + static void psxBios_DequeueCdIntr() { // a3 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0xa3]); psxBios_DequeueCdIntr_(); @@ -1822,47 +2013,6 @@ static void psxBios_get_cd_status() // a6 pc0 = ra; } -static void psxBios__card_info() { // ab - PSXBIOS_LOG("psxBios_%s: %x\n", biosA0n[0xab], a0); - u32 ret, port; - storeRam32(A_CARD_CHAN1, a0); - port = a0 >> 4; - - switch (port) { - case 0x0: - case 0x1: - ret = 0x0004; - if (McdDisable[port & 1]) - ret = 0x0100; - break; - default: - PSXBIOS_LOG("psxBios_%s: UNKNOWN PORT 0x%x\n", biosA0n[0xab], a0); - ret = 0x0302; - break; - } - - if (McdDisable[0] && McdDisable[1]) - ret = 0x0100; - - DeliverEvent(0xf0000011, 0x0004); -// DeliverEvent(0xf4000001, 0x0004); - DeliverEvent(0xf4000001, ret); - v0 = 1; pc0 = ra; -} - -void psxBios__card_load() { // ac -#ifdef PSXBIOS_LOG - PSXBIOS_LOG("psxBios_%s: %x\n", biosA0n[0xac], a0); -#endif - - storeRam32(A_CARD_CHAN1, a0); - -// DeliverEvent(0xf0000011, 0x0004); - DeliverEvent(0xf4000001, 0x0004); - - v0 = 1; pc0 = ra; -} - static void psxBios_GetSystemInfo() { // b4 u32 ret = 0; //PSXBIOS_LOG("psxBios_%s %x\n", biosA0n[0xb4], a0); @@ -1960,13 +2110,13 @@ void psxBios_ResetRCnt() { // 06 } static u32 DeliverEvent(u32 class, u32 spec) { - EvCB *ev = (EvCB *)loadRam32ptr(A_TT_EvCB); + EvCB *ev, *ev_first = (EvCB *)loadRam32ptr(A_TT_EvCB); u32 evcb_len = loadRam32(A_TT_EvCB + 4); u32 ret = loadRam32(A_TT_EvCB) + evcb_len; u32 i, lim = evcb_len / 0x1c; //printf("%s %08x %x\n", __func__, class, spec); - for (i = 0; i < lim; i++, ev++) { + for (i = 0, ev = ev_first; i < lim; i++, ev++) { use_cycles(8); if (SWAP32(ev->status) != EvStACTIVE) continue; @@ -1979,12 +2129,17 @@ static u32 DeliverEvent(u32 class, u32 spec) { use_cycles(6); ret = SWAP32(ev->mode); if (ret == EvMdMARK) { + if (ev->status != SWAP32(EvStALREADY)) + PSXBIOS_EV_LOG("DeliverEvent %08x %x (%08zx) set\n", + class, spec, (ev - ev_first) | 0xf1000000u); ev->status = SWAP32(EvStALREADY); continue; } use_cycles(8); if (ret == EvMdCALL) { ret = SWAP32(ev->fhandler); + PSXBIOS_EV_LOG("DeliverEvent %08x %x (%08zx) cb %x\n", + class, spec, (ev - ev_first) | 0xf1000000u, ret); if (ret) { v0 = ret; softCall(ret); @@ -2117,13 +2272,17 @@ static void psxBios_TestEvent() { // 0b mips_return_c(ret, 15); } -static void psxBios_EnableEvent() { // 0c +static void EnableEvent(u32 ev, int do_log) { u32 base = loadRam32(A_TT_EvCB); - u32 status = loadRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4); - PSXBIOS_LOG("psxBios_%s %x (%x)\n", biosB0n[0x0c], a0, status); + u32 status = loadRam32(base + (ev & 0xffff) * sizeof(EvCB) + 4); + if (do_log) + PSXBIOS_LOG("psxBios_%s %x (%x)\n", biosB0n[0x0c], ev, status); if (status != EvStUNUSED) - storeRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4, EvStACTIVE); + storeRam32(base + (ev & 0xffff) * sizeof(EvCB) + 4, EvStACTIVE); +} +static void psxBios_EnableEvent() { // 0c + EnableEvent(a0, 1); mips_return_c(1, 15); } @@ -2762,9 +2921,14 @@ void psxBios_delete() { // 45 } void psxBios_InitCARD() { // 4a + u8 *ram8 = (u8 *)psxM; u32 *ram32 = (u32 *)psxM; PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x4a], a0); write_chain(ram32 + A_PADCRD_CHN_E/4, 0, 0x49bc, 0x4a4c); + //card_error = 0; + ram8[A_CARD_ISLOT] = 0; + ram8[A_CARD_STATUS1] = 1; + ram8[A_CARD_STATUS2] = 1; // (maybe) todo: early_card_irq, etc ram32[A_PAD_IRQR_ENA/4] = SWAP32(a0); @@ -2800,23 +2964,19 @@ void psxBios__card_write() { // 0x4e void *pa2 = Ra2; int port; -#ifdef PSXBIOS_LOG - PSXBIOS_LOG("psxBios_%s: %x,%x,%x\n", biosB0n[0x4e], a0, a1, a2); -#endif - /* - Function also accepts sector 400h (a bug). - But notaz said we shouldn't allow sector 400h because it can corrupt the emulator. - */ - if (!(a1 <= 0x3FF)) + PSXBIOS_LOG("psxBios_%s %02x,%x,%x\n", biosB0n[0x4e], a0, a1, a2); + // function also accepts sector 400h (a bug), + // but what actually happens then? + if (a1 > 0x400) { /* Invalid sectors */ v0 = 0; pc0 = ra; return; } - storeRam32(A_CARD_CHAN1, a0); + storeRam32(A_CARD_ACHAN, a0); port = a0 >> 4; - if (pa2 != INVALID_PTR) { + if (pa2 != INVALID_PTR && a1 < 0x400) { if (port == 0) { memcpy(Mcd1Data + a1 * 128, pa2, 128); SaveMcd(Config.Mcd1, Mcd1Data, a1 * 128, 128); @@ -2826,33 +2986,27 @@ void psxBios__card_write() { // 0x4e } } - DeliverEvent(0xf0000011, 0x0004); -// DeliverEvent(0xf4000001, 0x0004); + storeRam8(A_CARD_STATUS1 + port, 4); // busy/write + storeRam32(A_CARD_HANDLER, CARD_HARDLER_READ); v0 = 1; pc0 = ra; } -void psxBios__card_read() { // 0x4f +static void psxBios__card_read() { // 0x4f void *pa2 = Ra2; int port; -#ifdef PSXBIOS_LOG - PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x4f]); -#endif - /* - Function also accepts sector 400h (a bug). - But notaz said we shouldn't allow sector 400h because it can corrupt the emulator. - */ - if (!(a1 <= 0x3FF)) + PSXBIOS_LOG("psxBios_%s %x,%x,%x\n", biosB0n[0x4f], a0, a1, a2); + if (a1 > 0x400) { /* Invalid sectors */ v0 = 0; pc0 = ra; return; } - storeRam32(A_CARD_CHAN1, a0); + storeRam32(A_CARD_ACHAN, a0); port = a0 >> 4; - if (pa2 != INVALID_PTR) { + if (pa2 != INVALID_PTR && a1 < 0x400) { if (port == 0) { memcpy(pa2, Mcd1Data + a1 * 128, 128); } else { @@ -2860,8 +3014,8 @@ void psxBios__card_read() { // 0x4f } } - DeliverEvent(0xf0000011, 0x0004); -// DeliverEvent(0xf4000001, 0x0004); + storeRam8(A_CARD_STATUS1 + port, 2); // busy/read + storeRam32(A_CARD_HANDLER, CARD_HARDLER_READ); v0 = 1; pc0 = ra; } @@ -2941,12 +3095,11 @@ void psxBios_GetB0Table() { // 57 } static void psxBios__card_chan() { // 0x58 - u32 ret; - PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x58]); - - // todo: should return active slot chan + // todo: should return active slot channel // (active - which was last processed by irq code) - ret = loadRam32(A_CARD_CHAN1); + u32 ret = loadRam32(A_CARD_ACHAN); + PSXBIOS_LOG("psxBios_%s -> %02x\n", biosB0n[0x58], ret); + mips_return_c(ret, 8); } @@ -2960,17 +3113,111 @@ static void psxBios_ChangeClearPad() { // 5b } static void psxBios__card_status() { // 5c - PSXBIOS_LOG("psxBios_%s %x\n", biosB0n[0x5c], a0); + u8 s = loadRam8(A_CARD_STATUS1 + a0); + PSXBIOS_LOG("psxBios_%s %x -> %x\n", biosB0n[0x5c], a0, s); - v0 = 1; // ready - pc0 = ra; + mips_return_c(s, 5); } static void psxBios__card_wait() { // 5d - PSXBIOS_LOG("psxBios_%s %x\n", biosB0n[0x5d], a0); + u8 s = loadRam8(A_CARD_STATUS1 + a0); + PSXBIOS_LOG("psxBios_%s %x -> %x\n", biosB0n[0x5d], a0, s); - v0 = 1; // ready - pc0 = ra; + // todo + if (!(s & 1)) + log_unhandled("%s %x\n", __func__, s); + + mips_return_c(s, 11); +} + +static void psxBios__card_info() { // A ab + PSXBIOS_LOG("psxBios_%s %02x\n", biosA0n[0xab], a0); + u32 ret, port; + storeRam32(A_CARD_ACHAN, a0); + port = a0 >> 4; + + switch (port) { + case 0x0: + case 0x1: + ret = 0x0004; + if (McdDisable[port & 1]) + ret = 0x0100; + break; + default: + PSXBIOS_LOG("psxBios_%s: UNKNOWN PORT 0x%x\n", biosA0n[0xab], a0); + ret = 0x0302; + break; + } + + if (McdDisable[0] && McdDisable[1]) + ret = 0x0100; + + if (ret == 4) { + // deliver from card_vint_handler() + storeRam8(A_CARD_STATUS1 + port, 8); // busy/info + storeRam32(A_CARD_HANDLER, CARD_HARDLER_INFO); + } else { + DeliverEvent(0xf4000001, ret); + DeliverEvent(0xf0000011, 0x0004); // ? + } + mips_return(1); +} + +static void psxBios__card_load() { // A ac + PSXBIOS_LOG("psxBios_%s %02x\n", biosA0n[0xac], a0); + + storeRam32(A_CARD_ACHAN, a0); + +// DeliverEvent(0xf0000011, 0x0004); + DeliverEvent(0xf4000001, 0x0004); + + mips_return(1); +} + +static void card_vint_handler(void) { + u8 select, status; + u32 handler; + UnDeliverEvent(0xf0000011, 0x0004); + UnDeliverEvent(0xf0000011, 0x8000); + UnDeliverEvent(0xf0000011, 0x0100); + UnDeliverEvent(0xf0000011, 0x0200); + UnDeliverEvent(0xf0000011, 0x2000); + +#if 0 + select = loadRam8(A_CARD_ISLOT); + select = (select ^ 1) & 1; + storeRam8(A_CARD_ISLOT, select); +#else + select = loadRam8(A_CARD_ACHAN) >> 4; + storeRam8(A_CARD_ISLOT, select); +#endif + status = loadRam8(A_CARD_STATUS1 + select); + if (status & 1) + return; // done + + //psxBios_SysDeqIntRP_(0, 0x7540); + //psxBios_SysDeqIntRP_(0, 0x7540); + //card_state_machine = 0; + //card_error_flag = 0; + handler = loadRam32(A_CARD_HANDLER); + switch (handler) { + case CARD_HARDLER_INFO: + DeliverEvent(0xf4000001, 4); + DeliverEvent(0xf0000011, 4); + storeRam8(A_CARD_STATUS1 + select, 1); + storeRam32(A_CARD_HANDLER, 0); + break; + case CARD_HARDLER_WRITE: + case CARD_HARDLER_READ: + DeliverEvent(0xf0000011, 4); + storeRam8(A_CARD_STATUS1 + select, 1); + storeRam32(A_CARD_HANDLER, 0); + break; + case 0: + break; + default: + log_unhandled("%s: unhandled handler %x\n", __func__, handler); + } } /* System calls C0 */ @@ -2984,7 +3231,8 @@ static void psxBios_InitRCnt() { // 00 psxHwWrite16(0x1f801100 + i*0x10 + 8, 0); psxHwWrite16(0x1f801100 + i*0x10 + 0, 0); } - psxBios_SysEnqIntRP_(a0, 0x6d88); + for (i = 0; i < 4; i++) + psxBios_SysEnqIntRP_(a0, 0x6d58 + i * 0x10); mips_return_c(0, 9); } @@ -3161,7 +3409,7 @@ static const struct { { 0x1920, hleop_exc1_3_1 }, { 0x1794, hleop_exc1_3_2 }, { 0x2458, hleop_exc3_0_2 }, - { 0x49bc, hleop_exc_padcard1 }, + { 0x49bc, hleop_exc_padcard1 }, // hleExcPadCard1 { 0x4a4c, hleop_exc_padcard2 }, }; @@ -3224,7 +3472,7 @@ static void setup_tt(u32 tcb_cnt, u32 evcb_cnt, u32 stack) ram32[0x0150/4] = SWAPu32(0x6ee0); // DCB - device control ram32[0x0154/4] = SWAPu32(0x0320); // DCB size - storeRam32(p_excb + 0*4, 0x91e0); // chain0 + storeRam32(p_excb + 0*4, 0x0000); // chain0 storeRam32(p_excb + 2*4, 0x6d88); // chain1 storeRam32(p_excb + 4*4, 0x0000); // chain2 storeRam32(p_excb + 6*4, 0x6d98); // chain3 @@ -3234,12 +3482,8 @@ static void setup_tt(u32 tcb_cnt, u32 evcb_cnt, u32 stack) for (i = 1; i < tcb_cnt; i++) storeRam32(p_tcb + sizeof(TCB) * i, 0x1000); - // default events - storeRam32(A_CD_EVENTS + 0x00, OpenEvent(0xf0000003, 0x0010, EvMdMARK, 0)); - storeRam32(A_CD_EVENTS + 0x04, OpenEvent(0xf0000003, 0x0020, EvMdMARK, 0)); - storeRam32(A_CD_EVENTS + 0x08, OpenEvent(0xf0000003, 0x0040, EvMdMARK, 0)); - storeRam32(A_CD_EVENTS + 0x0c, OpenEvent(0xf0000003, 0x0080, EvMdMARK, 0)); - storeRam32(A_CD_EVENTS + 0x10, OpenEvent(0xf0000003, 0x8000, EvMdMARK, 0)); + psxBios_SysEnqIntRP_(0, 0x6da8); + setup_cd_irq_and_events(); storeRam32(A_CONF_EvCB, evcb_cnt); storeRam32(A_CONF_TCB, tcb_cnt); @@ -3382,8 +3626,8 @@ void psxBiosInit() { biosA0[0x09] = psxBios_putc; biosA0[0x0a] = psxBios_todigit; //biosA0[0x0b] = psxBios_atof; - //biosA0[0x0c] = psxBios_strtoul; - //biosA0[0x0d] = psxBios_strtol; + biosA0[0x0c] = psxBios_strtoul; + biosA0[0x0d] = psxBios_strtol; biosA0[0x0e] = psxBios_abs; biosA0[0x0f] = psxBios_labs; biosA0[0x10] = psxBios_atoi; @@ -3454,8 +3698,8 @@ void psxBiosInit() { biosA0[0x51] = psxBios_LoadExec; //biosA0[0x52] = psxBios_GetSysSp; //biosA0[0x53] = psxBios_sys_a0_53; - //biosA0[0x54] = psxBios__96_init_a54; - //biosA0[0x55] = psxBios__bu_init_a55; + biosA0[0x54] = psxBios_CdInit; + biosA0[0x55] = psxBios__bu_init; biosA0[0x56] = psxBios_CdRemove; //biosA0[0x57] = psxBios_sys_a0_57; //biosA0[0x58] = psxBios_sys_a0_58; @@ -3483,7 +3727,7 @@ void psxBiosInit() { //biosA0[0x6e] = psxBios_dev_card_rename; //biosA0[0x6f] = psxBios_dev_card_6f; biosA0[0x70] = psxBios__bu_init; - biosA0[0x71] = psxBios__96_init; + biosA0[0x71] = psxBios_CdInit; biosA0[0x72] = psxBios_CdRemove; //biosA0[0x73] = psxBios_sys_a0_73; //biosA0[0x74] = psxBios_sys_a0_74; @@ -3519,7 +3763,7 @@ void psxBiosInit() { biosA0[0x92] = hleExc0_1_1; biosA0[0x93] = hleExc0_0_1; //biosA0[0x94] = psxBios_sys_a0_94; - //biosA0[0x95] = psxBios_sys_a0_95; + biosA0[0x95] = psxBios_CdReset; //biosA0[0x96] = psxBios_AddCDROMDevice; //biosA0[0x97] = psxBios_AddMemCardDevide; //biosA0[0x98] = psxBios_DisableKernelIORedirection; @@ -3532,7 +3776,7 @@ void psxBiosInit() { biosA0[0x9f] = psxBios_SetMem; //biosA0[0xa0] = psxBios__boot; //biosA0[0xa1] = psxBios_SystemError; - //biosA0[0xa2] = psxBios_EnqueueCdIntr; + biosA0[0xa2] = psxBios_EnqueueCdIntr; biosA0[0xa3] = psxBios_DequeueCdIntr; //biosA0[0xa4] = psxBios_sys_a0_a4; //biosA0[0xa5] = psxBios_ReadSector; @@ -3739,6 +3983,7 @@ void psxBiosInit() { strcpy((char *)&ram32[0xeff0/4], "bu"); // default exception handler chains + // see also setup_cd_irq_and_events() write_chain(&ram32[0x91e0/4], 0x91d0, 0xbfc050a4, 0xbfc04fbc); // chain0.e0 write_chain(&ram32[0x91d0/4], 0x6da8, 0xbfc0506c, 0xbfc04dec); // chain0.e1 write_chain(&ram32[0x6da8/4], 0, 0, 0x1a00); // chain0.e2 @@ -3752,18 +3997,25 @@ void psxBiosInit() { // fill the api jumptables with fake entries as some games patch them // (or rather the funcs listed there) + // also trap the destination as some "Cheats Edition" thing overrides the + // dispatcher with a wrapper and then jumps to the table entries directly ptr = (u32 *)&psxM[A_A0_TABLE]; - for (i = 0; i < 256; i++) - ptr[i] = SWAP32(A_A0_DUMMY); - + for (i = 0; i < 256; i++) { + ptr[i] = SWAP32(A_A0_TRAPS + i*4); + ram32[A_A0_TRAPS/4 + i] = HLEOP(hleop_a0t); + } ptr = (u32 *)&psxM[A_B0_TABLE]; - for (i = 0; i < 256; i++) - ptr[i] = SWAP32(A_B0_DUMMY); + for (i = 0; i < 256; i++) { + ptr[i] = SWAP32(A_B0_TRAPS + i*4); + ram32[A_B0_TRAPS/4 + i] = HLEOP(hleop_b0t); + } // B(5b) is special because games patch (sometimes even jump to) // code at fixed offsets from it, nocash lists offsets: // patch: +3d8, +4dc, +594, +62c, +9c8, +1988 // call: +7a0=4b70, +884=4c54, +894=4c64 - ptr[0x5b] = SWAP32(A_B0_5B_DUMMY); // 0x43d0 + ptr[0x5b] = SWAP32(A_B0_5B_TRAP); // 0x43d0 + ram32[A_B0_5B_TRAP/4] = HLEOP(hleop_b0t); + ram32[0x4b70/4] = SWAP32(0x03e00008); // jr $ra // setPadOutputBuf ram32[0x4c54/4] = SWAP32(0x240e0001); // mov $t6, 1 @@ -3774,15 +4026,17 @@ void psxBiosInit() { ram32[0x4c68/4] = SWAP32(0xac000000 + A_PAD_IRQR_ENA); // sw $0, ... ptr = (u32 *)&psxM[A_C0_TABLE]; - for (i = 0; i < 256/2; i++) - ptr[i] = SWAP32(A_C0_DUMMY); + for (i = 0; i < 256/2; i++) { + ptr[i] = SWAP32(A_C0_TRAPS + i*4); + ram32[A_C0_TRAPS/4 + i] = HLEOP(hleop_c0t); + } ptr[6] = SWAP32(A_EXCEPTION); // more HLE traps - ram32[A_A0_DUMMY/4] = HLEOP(hleop_dummy); - ram32[A_B0_DUMMY/4] = HLEOP(hleop_dummy); - ram32[A_C0_DUMMY/4] = HLEOP(hleop_dummy); - ram32[A_B0_5B_DUMMY/4] = HLEOP(hleop_dummy); + ram32[A_A0_TRAPS/4 - 1] = HLEOP(hleop_dummy); + ram32[A_B0_TRAPS/4 - 1] = HLEOP(hleop_dummy); + ram32[A_C0_TRAPS/4 - 1] = HLEOP(hleop_dummy); + ram32[0x7ffc/4] = HLEOP(hleop_dummy); ram32[0x8000/4] = HLEOP(hleop_execret); ram32[A_EEXIT_PTR/4] = SWAP32(A_EEXIT_DEF); @@ -4009,9 +4263,8 @@ static void hleExcPadCard1(void) } if (loadRam32(A_PAD_ACK_VBL)) psxHwWrite16(0x1f801070, ~1); - if (loadRam32(A_CARD_IRQR_ENA)) { - // todo, maybe - } + if (loadRam32(A_CARD_IRQR_ENA)) + card_vint_handler(); mips_return_c(0, 18); } @@ -4097,7 +4350,8 @@ static void hleA0() { u32 call = t1 & 0xff; u32 entry = loadRam32(A_A0_TABLE + call * 4); - if (call < 192 && entry != A_A0_DUMMY) { + use_cycles(4+7); + if (call < 192 && entry != A_A0_TRAPS + call * 4) { PSXBIOS_LOG("custom A%02x %s(0x%x, ) addr=%08x ra=%08x\n", call, biosA0n[call], a0, entry, ra); softCall(entry); @@ -4116,10 +4370,11 @@ static void hleB0() { u32 entry = loadRam32(A_B0_TABLE + call * 4); int is_custom = 0; + use_cycles(4+7); if (call == 0x5b) - is_custom = entry != A_B0_5B_DUMMY; + is_custom = entry != A_B0_5B_TRAP; else - is_custom = entry != A_B0_DUMMY; + is_custom = entry != A_B0_TRAPS + call * 4; if (is_custom) { PSXBIOS_LOG("custom B%02x %s(0x%x, ) addr=%08x ra=%08x\n", call, biosB0n[call], a0, entry, ra); @@ -4138,7 +4393,8 @@ static void hleC0() { u32 call = t1 & 0xff; u32 entry = loadRam32(A_C0_TABLE + call * 4); - if (call < 128 && entry != A_C0_DUMMY) { + use_cycles(4+7); + if (call < 128 && entry != A_C0_TRAPS + call * 4) { PSXBIOS_LOG("custom C%02x %s(0x%x, ) addr=%08x ra=%08x\n", call, biosC0n[call], a0, entry, ra); softCall(entry); @@ -4152,6 +4408,47 @@ static void hleC0() { psxBranchTest(); } +static void hleA0t() { + u32 call = (pc0 - A_A0_TRAPS) / 4 - 1; + if (call >= 256u || !biosA0[call]) { + log_unhandled("unexpected A trap @%08x ra=%08x\n", pc0 - 4, ra); + mips_return_void_c(1000); + } + else + biosA0[call](); + + //printf("A(%02x) -> %x\n", call, v0); + psxBranchTest(); +} + +static void hleB0t() { + u32 call = (pc0 - A_B0_TRAPS) / 4 - 1; + if (pc0 - 4 == A_B0_5B_TRAP) + call = 0x5b; + if (call >= 256u || !biosB0[call]) { + log_unhandled("unexpected B trap @%08x ra=%08x\n", pc0 - 4, ra); + mips_return_void_c(1000); + } + else + biosB0[call](); + + //printf("B(%02x) -> %x\n", call, v0); + psxBranchTest(); +} + +static void hleC0t() { + u32 call = (pc0 - A_C0_TRAPS) / 4 - 1; + if (call >= 128u || !biosC0[call]) { + log_unhandled("unexpected C trap @%08x ra=%08x\n", pc0 - 4, ra); + mips_return_void_c(1000); + } + else + biosC0[call](); + + //printf("C(%02x) -> %x\n", call, v0); + psxBranchTest(); +} + // currently not used static void hleBootstrap() { CheckCdrom(); @@ -4173,7 +4470,7 @@ static void hleExecRet() { psxRegs.pc = ra; } -void (* const psxHLEt[24])() = { +void (* const psxHLEt[hleop_count_])() = { hleDummy, hleA0, hleB0, hleC0, hleBootstrap, hleExecRet, psxBiosException, hleDummy, hleExc0_0_1, hleExc0_0_2, @@ -4184,6 +4481,7 @@ void (* const psxHLEt[24])() = { hleExc1_3_1, hleExc1_3_2, hleExc3_0_2_defint, hleExcPadCard1, hleExcPadCard2, + hleA0t, hleB0t, hleC0t, }; void psxBiosCheckExe(u32 t_addr, u32 t_size, int loading_state) diff --git a/pcsx_rearmed/libpcsxcore/psxcommon.h b/pcsx_rearmed/libpcsxcore/psxcommon.h index 09fb39a4..a25e6252 100644 --- a/pcsx_rearmed/libpcsxcore/psxcommon.h +++ b/pcsx_rearmed/libpcsxcore/psxcommon.h @@ -150,8 +150,9 @@ typedef struct { struct { boolean cdr_read_timing; boolean gpu_slow_list_walking; - boolean gpu_busy; boolean gpu_centering; + boolean dualshock_init_analog; + boolean gpu_timing1024; } hacks; } PcsxConfig; diff --git a/pcsx_rearmed/libpcsxcore/psxdma.c b/pcsx_rearmed/libpcsxcore/psxdma.c index fa8f3394..25ee2f0d 100644 --- a/pcsx_rearmed/libpcsxcore/psxdma.c +++ b/pcsx_rearmed/libpcsxcore/psxdma.c @@ -67,7 +67,7 @@ void psxDma4(u32 madr, u32 bcr, u32 chcr) { // SPU // This should be much slower, like 12+ cycles/byte, it's like // that because the CPU runs too fast and fifo is not emulated. // See also set_dma_end(). - set_event(PSXINT_SPUDMA, words * 4); + set_event(PSXINT_SPUDMA, words * 4 * 4); return; case 0x01000200: //spu to cpu transfer @@ -78,7 +78,7 @@ void psxDma4(u32 madr, u32 bcr, u32 chcr) { // SPU psxCpu->Clear(madr, words_copy); HW_DMA4_MADR = SWAPu32(madr + words_copy * 4); - set_event(PSXINT_SPUDMA, words * 4); + set_event(PSXINT_SPUDMA, words * 4 * 4); return; default: @@ -90,6 +90,7 @@ void psxDma4(u32 madr, u32 bcr, u32 chcr) { // SPU DMA_INTERRUPT(4); } +#if 0 // Taken from PEOPS SOFTGPU static inline boolean CheckForEndlessLoop(u32 laddr, u32 *lUsedAddr) { if (laddr == lUsedAddr[1]) return TRUE; @@ -130,11 +131,12 @@ static u32 gpuDmaChainSize(u32 addr) { return size; } +#endif void psxDma2(u32 madr, u32 bcr, u32 chcr) { // GPU - u32 *ptr, madr_next, *madr_next_p, size; + u32 *ptr, madr_next, *madr_next_p; u32 words, words_left, words_max, words_copy; - int do_walking; + int cycles_sum, cycles_last_cmd = 0, do_walking; madr &= ~3; switch (chcr) { @@ -191,22 +193,23 @@ void psxDma2(u32 madr, u32 bcr, u32 chcr) { // GPU madr_next = 0xffffff; do_walking = Config.GpuListWalking; - if (do_walking < 0) + if (do_walking < 0 || Config.hacks.gpu_timing1024) do_walking = Config.hacks.gpu_slow_list_walking; madr_next_p = do_walking ? &madr_next : NULL; - size = GPU_dmaChain((u32 *)psxM, madr & 0x1fffff, madr_next_p); - if ((int)size <= 0) - size = gpuDmaChainSize(madr); + cycles_sum = GPU_dmaChain((u32 *)psxM, madr & 0x1fffff, + madr_next_p, &cycles_last_cmd); HW_DMA2_MADR = SWAPu32(madr_next); - // Tekken 3 = use 1.0 only (not 1.5x) + // a hack for Judge Dredd which is annoyingly sensitive to timing + if (Config.hacks.gpu_timing1024) + cycles_sum = 1024; - // Einhander = parse linked list in pieces (todo) - // Rebel Assault 2 = parse linked list in pieces (todo) - psxRegs.gpuIdleAfter = psxRegs.cycle + size + 16; - set_event(PSXINT_GPUDMA, size); + psxRegs.gpuIdleAfter = psxRegs.cycle + cycles_sum + cycles_last_cmd; + set_event(PSXINT_GPUDMA, cycles_sum); + //printf("%u dma2cf: %d,%d %08x\n", psxRegs.cycle, cycles_sum, + // cycles_last_cmd, HW_DMA2_MADR); return; default: @@ -221,11 +224,17 @@ void psxDma2(u32 madr, u32 bcr, u32 chcr) { // GPU void gpuInterrupt() { if (HW_DMA2_CHCR == SWAP32(0x01000401) && !(HW_DMA2_MADR & SWAP32(0x800000))) { - u32 size, madr_next = 0xffffff, madr = SWAPu32(HW_DMA2_MADR); - size = GPU_dmaChain((u32 *)psxM, madr & 0x1fffff, &madr_next); + u32 madr_next = 0xffffff, madr = SWAPu32(HW_DMA2_MADR); + int cycles_sum, cycles_last_cmd = 0; + cycles_sum = GPU_dmaChain((u32 *)psxM, madr & 0x1fffff, + &madr_next, &cycles_last_cmd); HW_DMA2_MADR = SWAPu32(madr_next); - psxRegs.gpuIdleAfter = psxRegs.cycle + size + 64; - set_event(PSXINT_GPUDMA, size); + if ((s32)(psxRegs.gpuIdleAfter - psxRegs.cycle) > 0) + cycles_sum += psxRegs.gpuIdleAfter - psxRegs.cycle; + psxRegs.gpuIdleAfter = psxRegs.cycle + cycles_sum + cycles_last_cmd; + set_event(PSXINT_GPUDMA, cycles_sum); + //printf("%u dma2cn: %d,%d %08x\n", psxRegs.cycle, cycles_sum, + // cycles_last_cmd, HW_DMA2_MADR); return; } if (HW_DMA2_CHCR & SWAP32(0x01000000)) @@ -242,6 +251,7 @@ void psxDma6(u32 madr, u32 bcr, u32 chcr) { PSXDMA_LOG("*** DMA6 OT *** %x addr = %x size = %x\n", chcr, madr, bcr); if (chcr == 0x11000002) { + madr &= ~3; mem = getDmaRam(madr, &words_max); if (mem == INVALID_PTR) { log_unhandled("bad6 dma madr %x\n", madr); diff --git a/pcsx_rearmed/libpcsxcore/psxhle.h b/pcsx_rearmed/libpcsxcore/psxhle.h index e6d2df81..a94d694f 100644 --- a/pcsx_rearmed/libpcsxcore/psxhle.h +++ b/pcsx_rearmed/libpcsxcore/psxhle.h @@ -39,9 +39,11 @@ enum hle_op { hleop_exc1_3_1, hleop_exc1_3_2, hleop_exc3_0_2, hleop_exc_padcard1, hleop_exc_padcard2, + hleop_a0t, hleop_b0t, hleop_c0t, + hleop_count_ // must be last }; -extern void (* const psxHLEt[24])(); +extern void (* const psxHLEt[hleop_count_])(); #ifdef __cplusplus } diff --git a/pcsx_rearmed/libpcsxcore/psxhw.c b/pcsx_rearmed/libpcsxcore/psxhw.c index 8179d959..0a468753 100644 --- a/pcsx_rearmed/libpcsxcore/psxhw.c +++ b/pcsx_rearmed/libpcsxcore/psxhw.c @@ -27,8 +27,6 @@ #include "cdrom.h" #include "gpu.h" -static u32 (*psxHwReadGpuSRptr)(void) = psxHwReadGpuSR; - void psxHwReset() { memset(psxH, 0, 0x10000); @@ -36,8 +34,6 @@ void psxHwReset() { cdrReset(); psxRcntInit(); HW_GPU_STATUS = SWAP32(0x10802000); - psxHwReadGpuSRptr = Config.hacks.gpu_busy - ? psxHwReadGpuSRbusyHack : psxHwReadGpuSR; } void psxHwWriteIstat(u32 value) @@ -121,18 +117,6 @@ u32 psxHwReadGpuSR(void) return v; } -// a hack due to poor timing of gpu idle bit -// to get rid of this, GPU draw times, DMAs, cpu timing has to fall within -// certain timing window or else games like "ToHeart" softlock -u32 psxHwReadGpuSRbusyHack(void) -{ - u32 v = psxHwReadGpuSR(); - static u32 hack; - if (!(hack++ & 3)) - v &= ~PSXGPU_nBUSY; - return v; -} - u8 psxHwRead8(u32 add) { u8 hard; @@ -254,7 +238,7 @@ u32 psxHwRead32(u32 add) { case 0x1124: hard = psxRcntRmode(2); break; case 0x1128: hard = psxRcntRtarget(2); break; case 0x1810: hard = GPU_readData(); break; - case 0x1814: hard = psxHwReadGpuSRptr(); break; + case 0x1814: hard = psxHwReadGpuSR(); break; case 0x1820: hard = mdecRead0(); break; case 0x1824: hard = mdecRead1(); break; diff --git a/pcsx_rearmed/libpcsxcore/psxhw.h b/pcsx_rearmed/libpcsxcore/psxhw.h index 574ee333..3017c901 100644 --- a/pcsx_rearmed/libpcsxcore/psxhw.h +++ b/pcsx_rearmed/libpcsxcore/psxhw.h @@ -93,7 +93,6 @@ void psxHwWriteChcr6(u32 value); void psxHwWriteDmaIcr32(u32 value); void psxHwWriteGpuSR(u32 value); u32 psxHwReadGpuSR(void); -u32 psxHwReadGpuSRbusyHack(void); #ifdef __cplusplus } diff --git a/pcsx_rearmed/plugins/dfsound/Makefile.c64p b/pcsx_rearmed/plugins/dfsound/Makefile.c64p index 5b977810..5942017e 100644 --- a/pcsx_rearmed/plugins/dfsound/Makefile.c64p +++ b/pcsx_rearmed/plugins/dfsound/Makefile.c64p @@ -1,6 +1,9 @@ ifndef C64_TOOLS_DSP_ROOT $(error need C64_TOOLS_DSP_ROOT) endif +ifndef TI_CGTOOLS +$(error need TI_CGTOOLS and stuff, source c64_tools/dsp/setenv.sh) +endif include $(C64_TOOLS_DSP_ROOT)/install.mk diff --git a/pcsx_rearmed/plugins/dfsound/dma.c b/pcsx_rearmed/plugins/dfsound/dma.c index 25a0aefd..6b4b63e9 100644 --- a/pcsx_rearmed/plugins/dfsound/dma.c +++ b/pcsx_rearmed/plugins/dfsound/dma.c @@ -51,7 +51,7 @@ void CALLBACK SPUreadDMAMem(unsigned short *pusPSXMem, int iSize, addr &= 0x7fffe; } if ((spu.spuCtrl & CTRL_IRQ) && irq_after < iSize * 2) { - log_unhandled("rdma spu irq: %x/%x+%x\n", irq_addr, spu.spuAddr, iSize * 2); + log_unhandled("rdma spu irq: %x/%x-%x\n", irq_addr, spu.spuAddr, addr); do_irq_io(irq_after); } spu.spuAddr = addr; @@ -68,7 +68,7 @@ void CALLBACK SPUwriteDMAMem(unsigned short *pusPSXMem, int iSize, unsigned int addr = spu.spuAddr, irq_addr = regAreaGet(H_SPUirqAddr) << 3; int i, irq_after; - do_samples_if_needed(cycles, 1, 2); + do_samples_if_needed(cycles + iSize*2 * 4, 1, 2); irq_after = (irq_addr - addr) & 0x7ffff; spu.bMemDirty = 1; @@ -87,11 +87,28 @@ void CALLBACK SPUwriteDMAMem(unsigned short *pusPSXMem, int iSize, } } if ((spu.spuCtrl & CTRL_IRQ) && irq_after < iSize * 2) { - log_unhandled("wdma spu irq: %x/%x+%x (%u)\n", - irq_addr, spu.spuAddr, iSize * 2, irq_after); + log_unhandled("%u wdma spu irq: %x/%x-%x (%u)\n", + cycles, irq_addr, spu.spuAddr, addr, irq_after); // this should be consistent with psxdma.c timing // might also need more delay like in set_dma_end() - do_irq_io(irq_after); + do_irq_io(irq_after * 4); + } + for (i = 0; i < MAXCHAN; i++) { + size_t ediff, p = spu.s_chan[i].pCurr - spu.spuMemC; + if (spu.s_chan[i].ADSRX.State == ADSR_RELEASE && !spu.s_chan[i].ADSRX.EnvelopeVol) + continue; + ediff = addr - p; + if (spu.spuAddr < p && p < spu.spuAddr + iSize * 2) { + log_unhandled("%u spu ch%02d play %zx dma %x-%x (%zd)\n", + cycles, i, p, spu.spuAddr, addr, ediff); + //exit(1); + } + // a hack for the super annoying timing issues in The Emperor's New Groove + // (which is a game bug, but tends to trigger more here) + if (ediff <= 0x20u) { + spu.s_chan[i].pCurr += ediff; + break; + } } spu.spuAddr = addr; set_dma_end(iSize, cycles); diff --git a/pcsx_rearmed/plugins/dfsound/dma.h b/pcsx_rearmed/plugins/dfsound/dma.h deleted file mode 100644 index 4982432b..00000000 --- a/pcsx_rearmed/plugins/dfsound/dma.h +++ /dev/null @@ -1,35 +0,0 @@ -/*************************************************************************** - dma.h - description - ------------------- - begin : Wed May 15 2002 - copyright : (C) 2002 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2002/05/15 - Pete -// - generic cleanup for the Peops release -// -//*************************************************************************// - -#ifndef __P_DMA_H__ -#define __P_DMA_H__ - -unsigned short CALLBACK SPUreadDMA(void); -void CALLBACK SPUreadDMAMem(unsigned short * pusPSXMem,int iSize); -void CALLBACK SPUwriteDMA(unsigned short val); -void CALLBACK SPUwriteDMAMem(unsigned short * pusPSXMem,int iSize); - -#endif /* __P_DMA_H__ */ diff --git a/pcsx_rearmed/plugins/dfsound/externals.h b/pcsx_rearmed/plugins/dfsound/externals.h index fef5f9cc..2b593ec7 100644 --- a/pcsx_rearmed/plugins/dfsound/externals.h +++ b/pcsx_rearmed/plugins/dfsound/externals.h @@ -89,17 +89,6 @@ typedef struct /////////////////////////////////////////////////////////// -// Tmp Flags - -// used for debug channel muting -#define FLAG_MUTE 1 - -// used for simple interpolation -#define FLAG_IPOL0 2 -#define FLAG_IPOL1 4 - -/////////////////////////////////////////////////////////// - // MAIN CHANNEL STRUCT typedef struct { @@ -225,6 +214,10 @@ typedef struct int iLeftXAVol; int iRightXAVol; + struct { // channel volume in the cd controller + unsigned char ll, lr, rl, rr; // see cdr.Attenuator* in cdrom.c + } cdv; // applied on spu side for easier emulation + unsigned int last_keyon_cycles; union { @@ -260,13 +253,17 @@ typedef struct sample_buf sb[MAXCHAN]; int interpolation; - sample_buf sb_thread[MAXCHAN]; + +#if P_HAVE_PTHREAD || defined(WANT_THREAD_CODE) + sample_buf * sb_thread; + sample_buf sb_thread_[MAXCHAN]; +#endif } SPUInfo; #define regAreaGet(offset) \ - spu.regArea[((offset) - 0xc00)>>1] + spu.regArea[((offset) - 0xc00) >> 1] #define regAreaGetCh(ch, offset) \ - spu.regArea[((ch<<4)|(offset))>>1] + spu.regArea[(((ch) << 4) | (offset)) >> 1] /////////////////////////////////////////////////////////// // SPU.C globals @@ -289,4 +286,7 @@ void do_irq_io(int cycles_after); #endif +void FeedXA(const xa_decode_t *xap); +void FeedCDDA(unsigned char *pcm, int nBytes); + #endif /* __P_SOUND_EXTERNALS_H__ */ diff --git a/pcsx_rearmed/plugins/dfsound/freeze.c b/pcsx_rearmed/plugins/dfsound/freeze.c index 8816a51c..bddf0ada 100644 --- a/pcsx_rearmed/plugins/dfsound/freeze.c +++ b/pcsx_rearmed/plugins/dfsound/freeze.c @@ -107,7 +107,7 @@ typedef struct ADSRInfoEx_orig ADSRX; // next ADSR settings (will be moved to active on sample start) } SPUCHAN_orig; -typedef struct +typedef struct SPUFreeze { char szSPUName[8]; uint32_t ulFreezeVersion; @@ -130,6 +130,14 @@ typedef struct SPUCHAN_orig s_chan[MAXCHAN]; + uint32_t cycles_dma_end; + uint32_t decode_dirty_ch; + uint32_t dwNoiseVal; + uint32_t dwNoiseCount; + uint32_t XARepeat; + uint32_t XALastVal; + uint32_t last_keyon_cycles; + } SPUOSSFreeze_t; //////////////////////////////////////////////////////////////////////// @@ -228,8 +236,8 @@ static void load_register(unsigned long reg, unsigned int cycles) // SPUFREEZE: called by main emu on savestate load/save //////////////////////////////////////////////////////////////////////// -long CALLBACK SPUfreeze(uint32_t ulFreezeMode, SPUFreeze_t * pF, - uint32_t cycles) +long CALLBACK SPUfreeze(unsigned int ulFreezeMode, SPUFreeze_t * pF, + unsigned int cycles) { SPUOSSFreeze_t * pFO = NULL; int i; @@ -250,6 +258,8 @@ long CALLBACK SPUfreeze(uint32_t ulFreezeMode, SPUFreeze_t * pF, if(ulFreezeMode==2) return 1; // info mode? ok, bye // save mode: + regAreaGet(H_SPUctrl) = spu.spuCtrl; + regAreaGet(H_SPUstat) = spu.spuStat; memcpy(pF->cSPURam,spu.spuMem,0x80000); // copy common infos memcpy(pF->cSPUPort,spu.regArea,0x200); @@ -293,6 +303,13 @@ long CALLBACK SPUfreeze(uint32_t ulFreezeMode, SPUFreeze_t * pF, pFO->xa_left = xa_left; pFO->cdda_left = cdda_left; pFO->cycles_played = spu.cycles_played; + pFO->cycles_dma_end = spu.cycles_dma_end; + pFO->decode_dirty_ch = spu.decode_dirty_ch; + pFO->dwNoiseVal = spu.dwNoiseVal; + pFO->dwNoiseCount = spu.dwNoiseCount; + pFO->XARepeat = spu.XARepeat; + pFO->XALastVal = spu.XALastVal; + pFO->last_keyon_cycles = spu.last_keyon_cycles; for(i=0;icSPURam,0x80000); // get ram memcpy(spu.regArea,pF->cSPUPort,0x200); spu.bMemDirty = 1; + spu.spuCtrl = regAreaGet(H_SPUctrl); + spu.spuStat = regAreaGet(H_SPUstat); if (!strcmp(pF->szSPUName,"PBOSS") && pF->ulFreezeVersion==5) pFO = LoadStateV5(pF, cycles); @@ -329,18 +348,35 @@ long CALLBACK SPUfreeze(uint32_t ulFreezeMode, SPUFreeze_t * pF, FeedCDDA((void *)pF->xaS.pcm, pFO->cdda_left * 4); } + // not in old savestates + spu.cycles_dma_end = 0; + spu.decode_dirty_ch = spu.dwChannelsAudible & 0x0a; + spu.dwNoiseVal = 0; + spu.dwNoiseCount = 0; + spu.XARepeat = 0; + spu.XALastVal = 0; + spu.last_keyon_cycles = cycles - 16*786u; + if (pFO && pF->ulFreezeSize >= sizeof(*pF) + sizeof(*pFO)) { + spu.cycles_dma_end = pFO->cycles_dma_end; + spu.decode_dirty_ch = pFO->decode_dirty_ch; + spu.dwNoiseVal = pFO->dwNoiseVal; + spu.dwNoiseCount = pFO->dwNoiseCount; + spu.XARepeat = pFO->XARepeat; + spu.XALastVal = pFO->XALastVal; + spu.last_keyon_cycles = pFO->last_keyon_cycles; + } + // repair some globals for(i=0;i<=62;i+=2) load_register(H_Reverb+i, cycles); load_register(H_SPUReverbAddr, cycles); load_register(H_SPUrvolL, cycles); load_register(H_SPUrvolR, cycles); - - load_register(H_SPUctrl, cycles); - load_register(H_SPUstat, cycles); load_register(H_CDLeft, cycles); load_register(H_CDRight, cycles); + // reverb + spu.rvb->StartAddr = regAreaGet(H_SPUReverbAddr) << 2; if (spu.rvb->CurrAddr < spu.rvb->StartAddr) spu.rvb->CurrAddr = spu.rvb->StartAddr; // fix to prevent new interpolations from crashing @@ -383,6 +419,7 @@ static SPUOSSFreeze_t * LoadStateV5(SPUFreeze_t * pF, uint32_t cycles) spu.s_chan[i].pCurr+=(uintptr_t)spu.spuMemC; spu.s_chan[i].pLoop+=(uintptr_t)spu.spuMemC; } + return pFO; } diff --git a/pcsx_rearmed/plugins/dfsound/gauss_i.h b/pcsx_rearmed/plugins/dfsound/gauss_i.h index 012cf701..e754347e 100644 --- a/pcsx_rearmed/plugins/dfsound/gauss_i.h +++ b/pcsx_rearmed/plugins/dfsound/gauss_i.h @@ -308,4 +308,4 @@ const int gauss[]={ 0xffffffff, 0x1307, 0x59b3, 0x12c7, }; -#endif \ No newline at end of file +#endif diff --git a/pcsx_rearmed/plugins/dfsound/psemuxa.h b/pcsx_rearmed/plugins/dfsound/psemuxa.h index 402d2733..11b748df 100644 --- a/pcsx_rearmed/plugins/dfsound/psemuxa.h +++ b/pcsx_rearmed/plugins/dfsound/psemuxa.h @@ -11,7 +11,7 @@ typedef struct int y0, y1; } ADPCM_Decode_t; -typedef struct +typedef struct xa_decode { int freq; int nbits; diff --git a/pcsx_rearmed/plugins/dfsound/registers.c b/pcsx_rearmed/plugins/dfsound/registers.c index 5d79f251..1e79c0e6 100644 --- a/pcsx_rearmed/plugins/dfsound/registers.c +++ b/pcsx_rearmed/plugins/dfsound/registers.c @@ -144,6 +144,7 @@ void CALLBACK SPUwriteRegister(unsigned long reg, unsigned short val, break; //-------------------------------------------------// case H_SPUctrl: + spu.spuStat = (spu.spuStat & ~0x3f) | (val & 0x3f); spu.spuStat &= ~STAT_IRQ | val; if (!(spu.spuCtrl & CTRL_IRQ)) { if (val & CTRL_IRQ) @@ -365,7 +366,7 @@ unsigned short CALLBACK SPUreadRegister(unsigned long reg, unsigned int cycles) return spu.spuCtrl; case H_SPUstat: - return (spu.spuStat & ~0x3F) | (spu.spuCtrl & 0x3F); + return spu.spuStat; case H_SPUaddr: return (unsigned short)(spu.spuAddr>>3); diff --git a/pcsx_rearmed/plugins/dfsound/reverb.c b/pcsx_rearmed/plugins/dfsound/reverb.c index de9b804a..c0ecea1d 100644 --- a/pcsx_rearmed/plugins/dfsound/reverb.c +++ b/pcsx_rearmed/plugins/dfsound/reverb.c @@ -177,7 +177,7 @@ static void REVERBPrep(void) REVERBInfo *rvb = spu.rvb; int space, t; - t = spu.regArea[(H_SPUReverbAddr - 0xc00) >> 1]; + t = regAreaGet(H_SPUReverbAddr); if (t == 0xFFFF || t <= 0x200) spu.rvb->StartAddr = spu.rvb->CurrAddr = 0; else if (spu.rvb->StartAddr != (t << 2)) diff --git a/pcsx_rearmed/plugins/dfsound/spu.c b/pcsx_rearmed/plugins/dfsound/spu.c index f2023881..0e4b154e 100644 --- a/pcsx_rearmed/plugins/dfsound/spu.c +++ b/pcsx_rearmed/plugins/dfsound/spu.c @@ -27,6 +27,7 @@ #include "registers.h" #include "out.h" #include "spu_config.h" +#include "spu.h" #ifdef __arm__ #include "arm_features.h" @@ -835,7 +836,7 @@ static void do_channels(int ns_to) mix_chan(spu.SSumLR, ns_to, s_chan->iLeftVolume, s_chan->iRightVolume); } - MixXA(spu.SSumLR, RVB, ns_to, spu.decode_pos); + MixCD(spu.SSumLR, RVB, ns_to, spu.decode_pos); if (spu.rvb->StartAddr) { if (do_rvb) @@ -1112,7 +1113,7 @@ static void sync_worker_thread(int force) work = &worker->i[worker->i_reaped & WORK_I_MASK]; thread_work_wait_sync(work, force); - MixXA(work->SSumLR, RVB, work->ns_to, work->decode_pos); + MixCD(work->SSumLR, RVB, work->ns_to, work->decode_pos); do_samples_finish(work->SSumLR, work->ns_to, work->channels_silent, work->decode_pos); @@ -1147,7 +1148,7 @@ void do_samples(unsigned int cycles_to, int do_direct) cycle_diff = cycles_to - spu.cycles_played; if (cycle_diff < -2*1048576 || cycle_diff > 2*1048576) { - //xprintf("desync %u %d\n", cycles_to, cycle_diff); + log_unhandled("desync %u %d\n", cycles_to, cycle_diff); spu.cycles_played = cycles_to; return; } @@ -1164,7 +1165,7 @@ void do_samples(unsigned int cycles_to, int do_direct) ns_to = (cycle_diff / 768 + 1) & ~1; if (ns_to > NSSIZE) { // should never happen - //xprintf("ns_to oflow %d %d\n", ns_to, NSSIZE); + log_unhandled("ns_to oflow %d %d\n", ns_to, NSSIZE); ns_to = NSSIZE; } @@ -1351,11 +1352,13 @@ void CALLBACK SPUupdate(void) // XA AUDIO -void CALLBACK SPUplayADPCMchannel(xa_decode_t *xap, unsigned int cycle, int unused) +void CALLBACK SPUplayADPCMchannel(xa_decode_t *xap, unsigned int cycle, int is_start) { if(!xap) return; if(!xap->freq) return; // no xa freq ? bye + if (is_start) + spu.XAPlay = spu.XAFeed = spu.XAStart; if (spu.XAPlay == spu.XAFeed) do_samples(cycle, 1); // catch up to prevent source underflows later @@ -1376,6 +1379,17 @@ int CALLBACK SPUplayCDDAchannel(short *pcm, int nbytes, unsigned int cycle, int return 0; } +void CALLBACK SPUsetCDvol(unsigned char ll, unsigned char lr, + unsigned char rl, unsigned char rr, unsigned int cycle) +{ + if (spu.XAPlay != spu.XAFeed || spu.CDDAPlay != spu.CDDAFeed) + do_samples(cycle, 1); + spu.cdv.ll = ll; + spu.cdv.lr = lr; + spu.cdv.rl = rl; + spu.cdv.rr = rr; +} + // to be called after state load void ClearWorkingState(void) { @@ -1476,6 +1490,8 @@ static void init_spu_thread(void) { int ret; + spu.sb_thread = spu.sb_thread_; + if (sysconf(_SC_NPROCESSORS_ONLN) <= 1) return; @@ -1537,7 +1553,10 @@ long CALLBACK SPUinit(void) int i; memset(&spu, 0, sizeof(spu)); - spu.spuMemC = calloc(1, 512 * 1024); + spu.spuMemC = calloc(1, 512 * 1024 + 16); + // a guard for runaway channels - End+Mute + spu.spuMemC[512 * 1024 + 1] = 1; + InitADSR(); spu.s_chan = calloc(MAXCHAN+1, sizeof(spu.s_chan[0])); // channel + 1 infos (1 is security for fmod handling) diff --git a/pcsx_rearmed/plugins/dfsound/spu.h b/pcsx_rearmed/plugins/dfsound/spu.h index 810ec07d..d49d9033 100644 --- a/pcsx_rearmed/plugins/dfsound/spu.h +++ b/pcsx_rearmed/plugins/dfsound/spu.h @@ -18,18 +18,29 @@ #ifndef __P_SPU_H__ #define __P_SPU_H__ -#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ -#define HTOLE16(x) __builtin_bswap16(x) -#define LE16TOH(x) __builtin_bswap16(x) -#else -#define HTOLE16(x) (x) -#define LE16TOH(x) (x) -#endif +struct SPUFreeze; +struct xa_decode; -void ClearWorkingState(void); -void CALLBACK SPUplayADPCMchannel(xa_decode_t *xap, unsigned int cycle, int is_start); +long CALLBACK SPUopen(void); +long CALLBACK SPUinit(void); +long CALLBACK SPUshutdown(void); +long CALLBACK SPUclose(void); +void CALLBACK SPUwriteRegister(unsigned long, unsigned short, unsigned int); +unsigned short CALLBACK SPUreadRegister(unsigned long, unsigned int); +void CALLBACK SPUregisterCallback(void (*cb)(int)); +void CALLBACK SPUregisterScheduleCb(void (*cb)(unsigned int)); +long CALLBACK SPUfreeze(unsigned int, struct SPUFreeze *, unsigned int); +void CALLBACK SPUasync(unsigned int, unsigned int); + +void CALLBACK SPUreadDMAMem(unsigned short * pusPSXMem,int iSize,unsigned int cycles); +void CALLBACK SPUwriteDMAMem(unsigned short * pusPSXMem,int iSize,unsigned int cycles); + +void CALLBACK SPUplayADPCMchannel(struct xa_decode *xap, unsigned int cycle, int is_start); int CALLBACK SPUplayCDDAchannel(short *pcm, int bytes, unsigned int cycle, int is_start); -void FeedXA(const xa_decode_t *xap); -void FeedCDDA(unsigned char *pcm, int nBytes); +void CALLBACK SPUsetCDvol(unsigned char ll, unsigned char lr, + unsigned char rl, unsigned char rr, unsigned int cycle); + +// internal +void ClearWorkingState(void); #endif /* __P_SPU_H__ */ diff --git a/pcsx_rearmed/plugins/dfsound/spu_c64x.c b/pcsx_rearmed/plugins/dfsound/spu_c64x.c index e0aa0da2..cb0d0b58 100644 --- a/pcsx_rearmed/plugins/dfsound/spu_c64x.c +++ b/pcsx_rearmed/plugins/dfsound/spu_c64x.c @@ -162,7 +162,7 @@ static void thread_work_wait_sync(struct work_item *work, int force) preload(work->SSumLR); preload(work->SSumLR + 64/4); - f.stale_caches = 1; // SB, spuMem + f.stale_caches = 1; // sb, spuMem if (limit == 0) printf("dsp: wait timeout\n"); @@ -188,7 +188,7 @@ static void thread_work_wait_sync(struct work_item *work, int force) static void thread_sync_caches(void) { if (f.stale_caches) { - f.dsp_cache_inv_virt(spu.SB, sizeof(spu.SB[0]) * SB_SIZE * 24); + f.dsp_cache_inv_virt(spu.sb_thread, sizeof(spu.sb_thread[0]) * MAXCHAN); f.dsp_cache_inv_virt(spu.spuMemC + 0x800, 0x800); if (spu.rvb->StartAddr) { int left = 0x40000 - spu.rvb->StartAddr; @@ -281,8 +281,7 @@ static void init_spu_thread(void) // override default allocations free(spu.spuMemC); spu.spuMemC = mem->spu_ram; - free(spu.SB); - spu.SB = mem->SB; + spu.sb_thread = mem->sb_thread; free(spu.s_chan); spu.s_chan = mem->in.s_chan; free(spu.rvb); @@ -326,7 +325,7 @@ static void exit_spu_thread(void) f.dsp_close(); spu.spuMemC = NULL; - spu.SB = NULL; + spu.sb_thread = spu.sb_thread_; spu.s_chan = NULL; spu.rvb = NULL; worker = NULL; diff --git a/pcsx_rearmed/plugins/dfsound/spu_c64x.h b/pcsx_rearmed/plugins/dfsound/spu_c64x.h index 56ede38d..dd07da1b 100644 --- a/pcsx_rearmed/plugins/dfsound/spu_c64x.h +++ b/pcsx_rearmed/plugins/dfsound/spu_c64x.h @@ -1,6 +1,9 @@ #ifndef __P_SPU_C64X_H__ #define __P_SPU_C64X_H__ +#include "externals.h" +#include "spu_config.h" + #define COMPONENT_NAME "pcsxr_spu" enum { @@ -10,10 +13,10 @@ enum { struct region_mem { unsigned char spu_ram[512 * 1024]; - int SB[SB_SIZE * 24]; + sample_buf sb_thread[MAXCHAN]; // careful not to lose ARM writes by DSP overwriting // with old data when it's writing out neighbor cachelines - int _pad1[128/4 - ((SB_SIZE * 24) & (128/4 - 1))]; + int _pad1[128/4 - ((sizeof(sample_buf) * MAXCHAN / 4) & (128/4 - 1))]; struct spu_in { // these are not to be modified by DSP SPUCHAN s_chan[24 + 1]; diff --git a/pcsx_rearmed/plugins/dfsound/spu_c64x_dspcode.c b/pcsx_rearmed/plugins/dfsound/spu_c64x_dspcode.c index 570da5ed..709519c1 100644 --- a/pcsx_rearmed/plugins/dfsound/spu_c64x_dspcode.c +++ b/pcsx_rearmed/plugins/dfsound/spu_c64x_dspcode.c @@ -114,7 +114,7 @@ static void do_processing(void) // nothing to do? Write out non-critical caches if (dirty) { syscalls.cache_wb(spu.spuMemC + 0x800, 0x800, 1); - syscalls.cache_wb(spu.SB, sizeof(spu.SB[0]) * SB_SIZE * 24, 1); + syscalls.cache_wb(spu.sb_thread, sizeof(spu.sb_thread[0]) * MAXCHAN, 1); if (had_rvb) { left = 0x40000 - spu.rvb->StartAddr; syscalls.cache_wb(spu.spuMem + spu.rvb->StartAddr, left * 2, 1); @@ -143,7 +143,7 @@ static unsigned int exec(dsp_component_cmd_t cmd, InitADSR(); spu.spuMemC = mem->spu_ram; - spu.SB = mem->SB; + spu.sb_thread = mem->sb_thread; spu.s_chan = mem->in.s_chan; spu.rvb = &mem->in.rvb; worker = &mem->worker; @@ -169,7 +169,7 @@ static unsigned int exec(dsp_component_cmd_t cmd, do_processing(); - syscalls.cache_inv(&mem->SB, sizeof(mem->SB), 0); + syscalls.cache_inv(&mem->sb_thread, sizeof(mem->sb_thread), 0); syscalls.cache_inv(&mem->in, sizeof(mem->in), 0); break; diff --git a/pcsx_rearmed/plugins/dfsound/stdafx.h b/pcsx_rearmed/plugins/dfsound/stdafx.h index 96335e38..71921a92 100644 --- a/pcsx_rearmed/plugins/dfsound/stdafx.h +++ b/pcsx_rearmed/plugins/dfsound/stdafx.h @@ -32,6 +32,14 @@ #define INLINE static inline #endif +#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define HTOLE16(x) __builtin_bswap16(x) +#define LE16TOH(x) __builtin_bswap16(x) +#else +#define HTOLE16(x) (x) +#define LE16TOH(x) (x) +#endif + #include "psemuxa.h" #endif /* __P_STDAFX_H__ */ diff --git a/pcsx_rearmed/plugins/dfsound/xa.c b/pcsx_rearmed/plugins/dfsound/xa.c index 08afc009..6b5433fb 100644 --- a/pcsx_rearmed/plugins/dfsound/xa.c +++ b/pcsx_rearmed/plugins/dfsound/xa.c @@ -39,13 +39,56 @@ static int gauss_window[8] = {0, 0, 0, 0, 0, 0, 0, 0}; // MIX XA & CDDA //////////////////////////////////////////////////////////////////////// -INLINE void MixXA(int *SSumLR, int *RVB, int ns_to, int decode_pos) +INLINE void SkipCD(int ns_to, int decode_pos) { int cursor = decode_pos; int ns; - short l, r; + + if(spu.XAPlay != spu.XAFeed) + { + for(ns = 0; ns < ns_to*2; ns += 2) + { + if(spu.XAPlay != spu.XAFeed) spu.XAPlay++; + if(spu.XAPlay == spu.XAEnd) spu.XAPlay=spu.XAStart; + + spu.spuMem[cursor] = 0; + spu.spuMem[cursor + 0x400/2] = 0; + cursor = (cursor + 1) & 0x1ff; + } + } + else if(spu.CDDAPlay != spu.CDDAFeed) + { + for(ns = 0; ns < ns_to*2; ns += 2) + { + if(spu.CDDAPlay != spu.CDDAFeed) spu.CDDAPlay++; + if(spu.CDDAPlay == spu.CDDAEnd) spu.CDDAPlay=spu.CDDAStart; + + spu.spuMem[cursor] = 0; + spu.spuMem[cursor + 0x400/2] = 0; + cursor = (cursor + 1) & 0x1ff; + } + } + spu.XALastVal = 0; +} + +INLINE void MixCD(int *SSumLR, int *RVB, int ns_to, int decode_pos) +{ + int vll = spu.iLeftXAVol * spu.cdv.ll >> 7; + int vrl = spu.iLeftXAVol * spu.cdv.rl >> 7; + int vlr = spu.iRightXAVol * spu.cdv.lr >> 7; + int vrr = spu.iRightXAVol * spu.cdv.rr >> 7; + int cursor = decode_pos; + int l1, r1, l, r; + int ns; uint32_t v = spu.XALastVal; + // note: spu volume doesn't affect cd capture + if ((spu.cdv.ll | spu.cdv.lr | spu.cdv.rl | spu.cdv.rr) == 0) + { + SkipCD(ns_to, decode_pos); + return; + } + if(spu.XAPlay != spu.XAFeed || spu.XARepeat > 0) { if(spu.XAPlay == spu.XAFeed) @@ -56,8 +99,11 @@ INLINE void MixXA(int *SSumLR, int *RVB, int ns_to, int decode_pos) if(spu.XAPlay != spu.XAFeed) v=*spu.XAPlay++; if(spu.XAPlay == spu.XAEnd) spu.XAPlay=spu.XAStart; - l = ((int)(short)v * spu.iLeftXAVol) >> 15; - r = ((int)(short)(v >> 16) * spu.iLeftXAVol) >> 15; + l1 = (short)v, r1 = (short)(v >> 16); + l = (l1 * vll + r1 * vrl) >> 15; + r = (r1 * vrr + l1 * vlr) >> 15; + ssat32_to_16(l); + ssat32_to_16(r); if (spu.spuCtrl & CTRL_CD) { SSumLR[ns+0] += l; @@ -84,8 +130,11 @@ INLINE void MixXA(int *SSumLR, int *RVB, int ns_to, int decode_pos) if(spu.CDDAPlay != spu.CDDAFeed) v=*spu.CDDAPlay++; if(spu.CDDAPlay == spu.CDDAEnd) spu.CDDAPlay=spu.CDDAStart; - l = ((int)(short)v * spu.iLeftXAVol) >> 15; - r = ((int)(short)(v >> 16) * spu.iLeftXAVol) >> 15; + l1 = (short)v, r1 = (short)(v >> 16); + l = (l1 * vll + r1 * vrl) >> 15; + r = (r1 * vrr + l1 * vlr) >> 15; + ssat32_to_16(l); + ssat32_to_16(r); if (spu.spuCtrl & CTRL_CD) { SSumLR[ns+0] += l; @@ -413,8 +462,10 @@ void FeedCDDA(unsigned char *pcm, int nBytes) { int space; space=(spu.CDDAPlay-spu.CDDAFeed-1)*4 & (CDDA_BUFFER_SIZE - 1); - if(space0) { diff --git a/pcsx_rearmed/plugins/dfxvideo/gpulib_if.c b/pcsx_rearmed/plugins/dfxvideo/gpulib_if.c index 29cf13f3..8a3f2f9a 100644 --- a/pcsx_rearmed/plugins/dfxvideo/gpulib_if.c +++ b/pcsx_rearmed/plugins/dfxvideo/gpulib_if.c @@ -319,16 +319,20 @@ void renderer_notify_scanout_change(int x, int y) { } +#include "../gpulib/gpu_timing.h" extern const unsigned char cmd_lengths[256]; -int do_cmd_list(uint32_t *list, int list_len, int *last_cmd) +int do_cmd_list(uint32_t *list, int list_len, + int *cycles_sum_out, int *cycles_last, int *last_cmd) { + int cpu_cycles_sum = 0, cpu_cycles = *cycles_last; unsigned int cmd = 0, len; uint32_t *list_start = list; uint32_t *list_end = list + list_len; for (; list < list_end; list += 1 + len) { + short *slist = (void *)list; cmd = GETLE32(list) >> 24; len = cmd_lengths[cmd]; if (list + 1 + len > list_end) { @@ -354,6 +358,8 @@ int do_cmd_list(uint32_t *list, int list_len, int *last_cmd) while(1) { + gput_sum(cpu_cycles_sum, cpu_cycles, gput_line(0)); + if(list_position >= list_end) { cmd = -1; goto breakloop; @@ -377,6 +383,8 @@ int do_cmd_list(uint32_t *list, int list_len, int *last_cmd) while(1) { + gput_sum(cpu_cycles_sum, cpu_cycles, gput_line(0)); + if(list_position >= list_end) { cmd = -1; goto breakloop; @@ -396,15 +404,43 @@ int do_cmd_list(uint32_t *list, int list_len, int *last_cmd) #ifdef TEST case 0xA0: // sys -> vid { - short *slist = (void *)list; - u32 load_width = LE2HOST32(slist[4]); - u32 load_height = LE2HOST32(slist[5]); + u32 load_width = LE2HOST16(slist[4]); + u32 load_height = LE2HOST16(slist[5]); u32 load_size = load_width * load_height; len += load_size / 2; break; } #endif + + // timing + case 0x02: + gput_sum(cpu_cycles_sum, cpu_cycles, + gput_fill(LE2HOST16(slist[4]) & 0x3ff, LE2HOST16(slist[5]) & 0x1ff)); + break; + case 0x20 ... 0x23: gput_sum(cpu_cycles_sum, cpu_cycles, gput_poly_base()); break; + case 0x24 ... 0x27: gput_sum(cpu_cycles_sum, cpu_cycles, gput_poly_base_t()); break; + case 0x28 ... 0x2B: gput_sum(cpu_cycles_sum, cpu_cycles, gput_quad_base()); break; + case 0x2C ... 0x2F: gput_sum(cpu_cycles_sum, cpu_cycles, gput_quad_base_t()); break; + case 0x30 ... 0x33: gput_sum(cpu_cycles_sum, cpu_cycles, gput_poly_base_g()); break; + case 0x34 ... 0x37: gput_sum(cpu_cycles_sum, cpu_cycles, gput_poly_base_gt()); break; + case 0x38 ... 0x3B: gput_sum(cpu_cycles_sum, cpu_cycles, gput_quad_base_g()); break; + case 0x3C ... 0x3F: gput_sum(cpu_cycles_sum, cpu_cycles, gput_quad_base_gt()); break; + case 0x40 ... 0x47: gput_sum(cpu_cycles_sum, cpu_cycles, gput_line(0)); break; + case 0x50 ... 0x57: gput_sum(cpu_cycles_sum, cpu_cycles, gput_line(0)); break; + case 0x60 ... 0x63: + gput_sum(cpu_cycles_sum, cpu_cycles, + gput_sprite(LE2HOST16(slist[4]) & 0x3ff, LE2HOST16(slist[5]) & 0x1ff)); + break; + case 0x64 ... 0x67: + gput_sum(cpu_cycles_sum, cpu_cycles, + gput_sprite(LE2HOST16(slist[6]) & 0x3ff, LE2HOST16(slist[7]) & 0x1ff)); + break; + case 0x68 ... 0x6B: gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(1, 1)); break; + case 0x70 ... 0x73: + case 0x74 ... 0x77: gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(8, 8)); break; + case 0x78 ... 0x7B: + case 0x7C ... 0x7F: gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(16, 16)); break; } } @@ -412,6 +448,8 @@ int do_cmd_list(uint32_t *list, int list_len, int *last_cmd) gpu.ex_regs[1] &= ~0x1ff; gpu.ex_regs[1] |= lGPUstatusRet & 0x1ff; + *cycles_sum_out += cpu_cycles_sum; + *cycles_last = cpu_cycles; *last_cmd = cmd; return list - list_start; } @@ -464,3 +502,5 @@ void renderer_set_config(const struct rearmed_cbs *cbs) cbs->pl_set_gpu_caps(0); set_vram(gpu.vram); } + +// vim:ts=2:shiftwidth=2:expandtab diff --git a/pcsx_rearmed/plugins/gpu-gles/gpulib_if.c b/pcsx_rearmed/plugins/gpu-gles/gpulib_if.c index 3c761823..ab95c641 100644 --- a/pcsx_rearmed/plugins/gpu-gles/gpulib_if.c +++ b/pcsx_rearmed/plugins/gpu-gles/gpulib_if.c @@ -521,7 +521,8 @@ void renderer_notify_scanout_change(int x, int y) extern const unsigned char cmd_lengths[256]; // XXX: mostly dupe code from soft peops -int do_cmd_list(unsigned int *list, int list_len, int *last_cmd) +int do_cmd_list(uint32_t *list, int list_len, + int *cycles_sum_out, int *cycles_last, int *last_cmd) { unsigned int cmd, len; unsigned int *list_start = list; diff --git a/pcsx_rearmed/plugins/gpu_neon/psx_gpu/psx_gpu.c b/pcsx_rearmed/plugins/gpu_neon/psx_gpu/psx_gpu.c index 62080f3f..b671a757 100644 --- a/pcsx_rearmed/plugins/gpu_neon/psx_gpu/psx_gpu.c +++ b/pcsx_rearmed/plugins/gpu_neon/psx_gpu/psx_gpu.c @@ -4194,10 +4194,10 @@ render_block_handler_struct render_sprite_block_handlers[] = void render_sprite(psx_gpu_struct *psx_gpu, s32 x, s32 y, u32 u, u32 v, - s32 width, s32 height, u32 flags, u32 color) + s32 *width, s32 *height, u32 flags, u32 color) { - s32 x_right = x + width - 1; - s32 y_bottom = y + height - 1; + s32 x_right = x + *width - 1; + s32 y_bottom = y + *height - 1; #ifdef PROFILE sprites++; @@ -4206,6 +4206,7 @@ void render_sprite(psx_gpu_struct *psx_gpu, s32 x, s32 y, u32 u, u32 v, if(invalidate_texture_cache_region_viewport(psx_gpu, x, y, x_right, y_bottom) == 0) { + *width = *height = 0; return; } @@ -4214,7 +4215,7 @@ void render_sprite(psx_gpu_struct *psx_gpu, s32 x, s32 y, u32 u, u32 v, u32 clip = psx_gpu->viewport_start_x - x; x += clip; u += clip; - width -= clip; + *width -= clip; } if(y < psx_gpu->viewport_start_y) @@ -4222,21 +4223,24 @@ void render_sprite(psx_gpu_struct *psx_gpu, s32 x, s32 y, u32 u, u32 v, s32 clip = psx_gpu->viewport_start_y - y; y += clip; v += clip; - height -= clip; + *height -= clip; } if(x_right > psx_gpu->viewport_end_x) - width -= x_right - psx_gpu->viewport_end_x; + *width -= x_right - psx_gpu->viewport_end_x; if(y_bottom > psx_gpu->viewport_end_y) - height -= y_bottom - psx_gpu->viewport_end_y; + *height -= y_bottom - psx_gpu->viewport_end_y; - if((width <= 0) || (height <= 0)) + if((*width <= 0) || (*height <= 0)) + { + *width = *height = 0; return; + } #ifdef PROFILE - span_pixels += width * height; - spans += height; + span_pixels += *width * *height; + spans += *height; #endif u32 render_state = flags & @@ -4273,7 +4277,7 @@ void render_sprite(psx_gpu_struct *psx_gpu, s32 x, s32 y, u32 u, u32 v, psx_gpu->render_block_handler = render_block_handler; ((setup_sprite_function_type *)render_block_handler->setup_blocks) - (psx_gpu, x, y, u, v, width, height, color); + (psx_gpu, x, y, u, v, *width, *height, color); } #define draw_pixel_line_mask_evaluate_yes() \ diff --git a/pcsx_rearmed/plugins/gpu_neon/psx_gpu/psx_gpu.h b/pcsx_rearmed/plugins/gpu_neon/psx_gpu/psx_gpu.h index bac2099c..6964a629 100644 --- a/pcsx_rearmed/plugins/gpu_neon/psx_gpu/psx_gpu.h +++ b/pcsx_rearmed/plugins/gpu_neon/psx_gpu/psx_gpu.h @@ -200,9 +200,12 @@ typedef struct u16 enhancement_scanout_eselect; // eviction selector u16 enhancement_current_buf; + u32 hack_disable_main:1; + u32 hack_texture_adj:1; + // Align up to 64 byte boundary to keep the upcoming buffers cache line // aligned, also make reachable with single immediate addition - u8 reserved_a[188 + 9*4 - 9*sizeof(void *)]; + u8 reserved_a[184 + 9*4 - 9*sizeof(void *)]; // 8KB block_struct blocks[MAX_BLOCKS_PER_ROW]; @@ -245,7 +248,7 @@ void render_block_move(psx_gpu_struct *psx_gpu, u32 source_x, u32 source_y, void render_triangle(psx_gpu_struct *psx_gpu, vertex_struct *vertexes, u32 flags); void render_sprite(psx_gpu_struct *psx_gpu, s32 x, s32 y, u32 u, u32 v, - s32 width, s32 height, u32 flags, u32 color); + s32 *width, s32 *height, u32 flags, u32 color); void render_line(psx_gpu_struct *gpu, vertex_struct *vertexes, u32 flags, u32 color, int double_resolution); @@ -255,7 +258,8 @@ void update_texture_8bpp_cache(psx_gpu_struct *psx_gpu); void flush_render_block_buffer(psx_gpu_struct *psx_gpu); void initialize_psx_gpu(psx_gpu_struct *psx_gpu, u16 *vram); -u32 gpu_parse(psx_gpu_struct *psx_gpu, u32 *list, u32 size, u32 *last_command); +u32 gpu_parse(psx_gpu_struct *psx_gpu, u32 *list, u32 size, + s32 *cpu_cycles_sum_out, s32 *cpu_cycles_last, u32 *last_command); void triangle_benchmark(psx_gpu_struct *psx_gpu); diff --git a/pcsx_rearmed/plugins/gpu_neon/psx_gpu/psx_gpu_arm_neon.S b/pcsx_rearmed/plugins/gpu_neon/psx_gpu/psx_gpu_arm_neon.S index f0ba39f3..ffbea043 100644 --- a/pcsx_rearmed/plugins/gpu_neon/psx_gpu/psx_gpu_arm_neon.S +++ b/pcsx_rearmed/plugins/gpu_neon/psx_gpu/psx_gpu_arm_neon.S @@ -6129,6 +6129,7 @@ function(scale2x_tiles8) mov r14, r2 0: + pld [r1, #1024*2] vld1.u16 { q0 }, [r1, :128]! vld1.u16 { q2 }, [r1, :128]! vmov q1, q0 diff --git a/pcsx_rearmed/plugins/gpu_neon/psx_gpu/psx_gpu_main.c b/pcsx_rearmed/plugins/gpu_neon/psx_gpu/psx_gpu_main.c index c7ce0ee4..435c51a2 100644 --- a/pcsx_rearmed/plugins/gpu_neon/psx_gpu/psx_gpu_main.c +++ b/pcsx_rearmed/plugins/gpu_neon/psx_gpu/psx_gpu_main.c @@ -135,6 +135,8 @@ int main(int argc, char *argv[]) FILE *state_file; FILE *list_file; u32 no_display = 0; + s32 dummy0 = 0; + u32 dummy1 = 0; if((argc != 3) && (argc != 4)) { @@ -213,7 +215,7 @@ int main(int argc, char *argv[]) init_counter(); #endif - gpu_parse(psx_gpu, list, size, NULL); + gpu_parse(psx_gpu, list, size, &dummy0, &dummy1); flush_render_block_buffer(psx_gpu); clear_stats(); @@ -222,7 +224,7 @@ int main(int argc, char *argv[]) u32 cycles = get_counter(); #endif - gpu_parse(psx_gpu, list, size, NULL); + gpu_parse(psx_gpu, list, size, &dummy0, &dummy1); flush_render_block_buffer(psx_gpu); #ifdef NEON_BUILD diff --git a/pcsx_rearmed/plugins/gpu_neon/psx_gpu/psx_gpu_parse.c b/pcsx_rearmed/plugins/gpu_neon/psx_gpu/psx_gpu_parse.c index 5f69919e..d81b7078 100644 --- a/pcsx_rearmed/plugins/gpu_neon/psx_gpu/psx_gpu_parse.c +++ b/pcsx_rearmed/plugins/gpu_neon/psx_gpu/psx_gpu_parse.c @@ -15,6 +15,7 @@ #include #include "common.h" +#include "../../gpulib/gpu_timing.h" #ifndef command_lengths const u8 command_lengths[256] = @@ -250,30 +251,32 @@ static void do_fill(psx_gpu_struct *psx_gpu, u32 x, u32 y, #define SET_Ex(r, v) #endif -u32 gpu_parse(psx_gpu_struct *psx_gpu, u32 *list, u32 size, u32 *last_command) +u32 gpu_parse(psx_gpu_struct *psx_gpu, u32 *list, u32 size, + s32 *cpu_cycles_sum_out, s32 *cpu_cycles_last, u32 *last_command) { vertex_struct vertexes[4] __attribute__((aligned(16))) = {}; u32 current_command = 0, command_length; + u32 cpu_cycles_sum = 0, cpu_cycles = *cpu_cycles_last; u32 *list_start = list; u32 *list_end = list + (size / 4); for(; list < list_end; list += 1 + command_length) { - s16 *list_s16 = (void *)list; - current_command = *list >> 24; - command_length = command_lengths[current_command]; - if (list + 1 + command_length > list_end) { - current_command = (u32)-1; - break; - } - - switch(current_command) - { - case 0x00: - break; - - case 0x02: + s16 *list_s16 = (void *)list; + current_command = *list >> 24; + command_length = command_lengths[current_command]; + if (list + 1 + command_length > list_end) { + current_command = (u32)-1; + break; + } + + switch(current_command) + { + case 0x00: + break; + + case 0x02: { u32 x = list_s16[2] & 0x3FF; u32 y = list_s16[3] & 0x1FF; @@ -282,10 +285,11 @@ u32 gpu_parse(psx_gpu_struct *psx_gpu, u32 *list, u32 size, u32 *last_command) u32 color = list[0] & 0xFFFFFF; do_fill(psx_gpu, x, y, width, height, color); - break; + gput_sum(cpu_cycles_sum, cpu_cycles, gput_fill(width, height)); + break; } - - case 0x20 ... 0x23: + + case 0x20 ... 0x23: { set_triangle_color(psx_gpu, list[0] & 0xFFFFFF); @@ -294,10 +298,11 @@ u32 gpu_parse(psx_gpu_struct *psx_gpu, u32 *list, u32 size, u32 *last_command) get_vertex_data_xy(2, 6); render_triangle(psx_gpu, vertexes, current_command); - break; + gput_sum(cpu_cycles_sum, cpu_cycles, gput_poly_base()); + break; } - case 0x24 ... 0x27: + case 0x24 ... 0x27: { set_clut(psx_gpu, list_s16[5]); set_texture(psx_gpu, list_s16[9]); @@ -308,10 +313,11 @@ u32 gpu_parse(psx_gpu_struct *psx_gpu, u32 *list, u32 size, u32 *last_command) get_vertex_data_xy_uv(2, 10); render_triangle(psx_gpu, vertexes, current_command); - break; + gput_sum(cpu_cycles_sum, cpu_cycles, gput_poly_base_t()); + break; } - case 0x28 ... 0x2B: + case 0x28 ... 0x2B: { set_triangle_color(psx_gpu, list[0] & 0xFFFFFF); @@ -322,10 +328,11 @@ u32 gpu_parse(psx_gpu_struct *psx_gpu, u32 *list, u32 size, u32 *last_command) render_triangle(psx_gpu, vertexes, current_command); render_triangle(psx_gpu, &(vertexes[1]), current_command); - break; + gput_sum(cpu_cycles_sum, cpu_cycles, gput_quad_base()); + break; } - case 0x2C ... 0x2F: + case 0x2C ... 0x2F: { set_clut(psx_gpu, list_s16[5]); set_texture(psx_gpu, list_s16[9]); @@ -338,23 +345,22 @@ u32 gpu_parse(psx_gpu_struct *psx_gpu, u32 *list, u32 size, u32 *last_command) render_triangle(psx_gpu, vertexes, current_command); render_triangle(psx_gpu, &(vertexes[1]), current_command); - break; + gput_sum(cpu_cycles_sum, cpu_cycles, gput_quad_base_t()); + break; } - case 0x30 ... 0x33: + case 0x30 ... 0x33: { get_vertex_data_xy_rgb(0, 0); get_vertex_data_xy_rgb(1, 4); get_vertex_data_xy_rgb(2, 8); render_triangle(psx_gpu, vertexes, current_command); - break; + gput_sum(cpu_cycles_sum, cpu_cycles, gput_poly_base_g()); + break; } - case 0x34: - case 0x35: - case 0x36: - case 0x37: + case 0x34 ... 0x37: { set_clut(psx_gpu, list_s16[5]); set_texture(psx_gpu, list_s16[11]); @@ -364,13 +370,11 @@ u32 gpu_parse(psx_gpu_struct *psx_gpu, u32 *list, u32 size, u32 *last_command) get_vertex_data_xy_uv_rgb(2, 12); render_triangle(psx_gpu, vertexes, current_command); - break; + gput_sum(cpu_cycles_sum, cpu_cycles, gput_poly_base_gt()); + break; } - case 0x38: - case 0x39: - case 0x3A: - case 0x3B: + case 0x38 ... 0x3B: { get_vertex_data_xy_rgb(0, 0); get_vertex_data_xy_rgb(1, 4); @@ -379,13 +383,11 @@ u32 gpu_parse(psx_gpu_struct *psx_gpu, u32 *list, u32 size, u32 *last_command) render_triangle(psx_gpu, vertexes, current_command); render_triangle(psx_gpu, &(vertexes[1]), current_command); - break; + gput_sum(cpu_cycles_sum, cpu_cycles, gput_quad_base_g()); + break; } - case 0x3C: - case 0x3D: - case 0x3E: - case 0x3F: + case 0x3C ... 0x3F: { set_clut(psx_gpu, list_s16[5]); set_texture(psx_gpu, list_s16[11]); @@ -397,10 +399,11 @@ u32 gpu_parse(psx_gpu_struct *psx_gpu, u32 *list, u32 size, u32 *last_command) render_triangle(psx_gpu, vertexes, current_command); render_triangle(psx_gpu, &(vertexes[1]), current_command); - break; + gput_sum(cpu_cycles_sum, cpu_cycles, gput_quad_base_gt()); + break; } - case 0x40 ... 0x47: + case 0x40 ... 0x47: { vertexes[0].x = list_s16[2] + psx_gpu->offset_x; vertexes[0].y = list_s16[3] + psx_gpu->offset_y; @@ -408,10 +411,11 @@ u32 gpu_parse(psx_gpu_struct *psx_gpu, u32 *list, u32 size, u32 *last_command) vertexes[1].y = list_s16[5] + psx_gpu->offset_y; render_line(psx_gpu, vertexes, current_command, list[0], 0); - break; + gput_sum(cpu_cycles_sum, cpu_cycles, gput_line(0)); + break; } - case 0x48 ... 0x4F: + case 0x48 ... 0x4F: { u32 num_vertexes = 1; u32 *list_position = &(list[2]); @@ -429,6 +433,7 @@ u32 gpu_parse(psx_gpu_struct *psx_gpu, u32 *list, u32 size, u32 *last_command) vertexes[1].y = (xy >> 16) + psx_gpu->offset_y; render_line(psx_gpu, vertexes, current_command, list[0], 0); + gput_sum(cpu_cycles_sum, cpu_cycles, gput_line(0)); list_position++; num_vertexes++; @@ -448,7 +453,7 @@ u32 gpu_parse(psx_gpu_struct *psx_gpu, u32 *list, u32 size, u32 *last_command) break; } - case 0x50 ... 0x57: + case 0x50 ... 0x57: { vertexes[0].r = list[0] & 0xFF; vertexes[0].g = (list[0] >> 8) & 0xFF; @@ -463,7 +468,8 @@ u32 gpu_parse(psx_gpu_struct *psx_gpu, u32 *list, u32 size, u32 *last_command) vertexes[1].y = list_s16[7] + psx_gpu->offset_y; render_line(psx_gpu, vertexes, current_command, 0, 0); - break; + gput_sum(cpu_cycles_sum, cpu_cycles, gput_line(0)); + break; } case 0x58 ... 0x5F: @@ -493,6 +499,7 @@ u32 gpu_parse(psx_gpu_struct *psx_gpu, u32 *list, u32 size, u32 *last_command) vertexes[1].y = (xy >> 16) + psx_gpu->offset_y; render_line(psx_gpu, vertexes, current_command, 0, 0); + gput_sum(cpu_cycles_sum, cpu_cycles, gput_line(0)); list_position += 2; num_vertexes++; @@ -512,101 +519,103 @@ u32 gpu_parse(psx_gpu_struct *psx_gpu, u32 *list, u32 size, u32 *last_command) break; } - case 0x60 ... 0x63: + case 0x60 ... 0x63: { u32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x); u32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y); - u32 width = list_s16[4] & 0x3FF; - u32 height = list_s16[5] & 0x1FF; + s32 width = list_s16[4] & 0x3FF; + s32 height = list_s16[5] & 0x1FF; - render_sprite(psx_gpu, x, y, 0, 0, width, height, current_command, list[0]); - break; + render_sprite(psx_gpu, x, y, 0, 0, &width, &height, + current_command, list[0]); + gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(width, height)); + break; } - case 0x64 ... 0x67: + case 0x64 ... 0x67: { u32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x); u32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y); u32 uv = list_s16[4]; - u32 width = list_s16[6] & 0x3FF; - u32 height = list_s16[7] & 0x1FF; + s32 width = list_s16[6] & 0x3FF; + s32 height = list_s16[7] & 0x1FF; set_clut(psx_gpu, list_s16[5]); - render_sprite(psx_gpu, x, y, uv & 0xFF, (uv >> 8) & 0xFF, width, height, - current_command, list[0]); - break; + render_sprite(psx_gpu, x, y, uv & 0xFF, (uv >> 8) & 0xFF, + &width, &height, current_command, list[0]); + gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(width, height)); + break; } - case 0x68: - case 0x69: - case 0x6A: - case 0x6B: + case 0x68 ... 0x6B: { s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x); s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y); + s32 width = 1, height = 1; - render_sprite(psx_gpu, x, y, 0, 0, 1, 1, current_command, list[0]); - break; + render_sprite(psx_gpu, x, y, 0, 0, &width, &height, + current_command, list[0]); + gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(1, 1)); + break; } - case 0x70: - case 0x71: - case 0x72: - case 0x73: + case 0x70 ... 0x73: { s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x); s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y); + s32 width = 8, height = 8; - render_sprite(psx_gpu, x, y, 0, 0, 8, 8, current_command, list[0]); - break; + render_sprite(psx_gpu, x, y, 0, 0, &width, &height, + current_command, list[0]); + gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(width, height)); + break; } - case 0x74: - case 0x75: - case 0x76: - case 0x77: + case 0x74 ... 0x77: { s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x); s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y); u32 uv = list_s16[4]; + s32 width = 8, height = 8; set_clut(psx_gpu, list_s16[5]); - render_sprite(psx_gpu, x, y, uv & 0xFF, (uv >> 8) & 0xFF, 8, 8, - current_command, list[0]); - break; + render_sprite(psx_gpu, x, y, uv & 0xFF, (uv >> 8) & 0xFF, + &width, &height, current_command, list[0]); + gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(width, height)); + break; } - case 0x78: - case 0x79: - case 0x7A: - case 0x7B: + case 0x78 ... 0x7B: { s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x); s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y); + s32 width = 16, height = 16; - render_sprite(psx_gpu, x, y, 0, 0, 16, 16, current_command, list[0]); - break; + render_sprite(psx_gpu, x, y, 0, 0, &width, &height, + current_command, list[0]); + gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(width, height)); + break; } - case 0x7C: - case 0x7D: - case 0x7E: - case 0x7F: + case 0x7C ... 0x7F: { s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x); s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y); u32 uv = list_s16[4]; + s32 width = 16, height = 16; set_clut(psx_gpu, list_s16[5]); - render_sprite(psx_gpu, x, y, uv & 0xFF, (uv >> 8) & 0xFF, 16, 16, - current_command, list[0]); - break; + render_sprite(psx_gpu, x, y, uv & 0xFF, (uv >> 8) & 0xFF, + &width, &height, current_command, list[0]); + gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(width, height)); + break; } #ifdef PCSX + case 0x1F: // irq? case 0x80 ... 0x9F: // vid -> vid case 0xA0 ... 0xBF: // sys -> vid case 0xC0 ... 0xDF: // vid -> sys @@ -643,14 +652,14 @@ u32 gpu_parse(psx_gpu_struct *psx_gpu, u32 *list, u32 size, u32 *last_command) render_block_copy(psx_gpu, (u16 *)&(list_s16[6]), load_x, load_y, load_width, load_height, load_width); - break; + break; } case 0xC0 ... 0xDF: // vid -> sys break; #endif - case 0xE1: + case 0xE1: set_texture(psx_gpu, list[0]); if(list[0] & (1 << 9)) @@ -659,10 +668,10 @@ u32 gpu_parse(psx_gpu_struct *psx_gpu, u32 *list, u32 size, u32 *last_command) psx_gpu->render_state_base &= ~RENDER_STATE_DITHER; psx_gpu->display_area_draw_enable = (list[0] >> 10) & 0x1; - SET_Ex(1, list[0]); - break; + SET_Ex(1, list[0]); + break; - case 0xE2: + case 0xE2: { // TODO: Clean u32 texture_window_settings = list[0]; @@ -751,11 +760,11 @@ u32 gpu_parse(psx_gpu_struct *psx_gpu, u32 *list, u32 size, u32 *last_command) psx_gpu->offset_x = offset_x >> 21; psx_gpu->offset_y = offset_y >> 21; - SET_Ex(5, list[0]); - break; - } + SET_Ex(5, list[0]); + break; + } - case 0xE6: + case 0xE6: { u32 mask_settings = list[0]; u16 mask_msb = mask_settings << 15; @@ -771,18 +780,19 @@ u32 gpu_parse(psx_gpu_struct *psx_gpu, u32 *list, u32 size, u32 *last_command) psx_gpu->mask_msb = mask_msb; } - SET_Ex(6, list[0]); - break; + SET_Ex(6, list[0]); + break; } - default: - break; - } + default: + break; + } } breakloop: - if (last_command != NULL) - *last_command = current_command; + *cpu_cycles_sum_out += cpu_cycles_sum; + *cpu_cycles_last = cpu_cycles; + *last_command = current_command; return list - list_start; } @@ -1008,8 +1018,6 @@ void scale2x_tiles8(void *dst, const void *src, int w8, int h) } #endif -static int disable_main_render; - // simple check for a case where no clipping is used // - now handled by adjusting the viewport static int check_enhanced_range(psx_gpu_struct *psx_gpu, int x, int y) @@ -1055,6 +1063,7 @@ static void patch_v(vertex_struct *vertex_ptrs, int count, int old, int new) vertex_ptrs[i].v = new; } +// this sometimes does more harm than good, like in PE2 static void uv_hack(vertex_struct *vertex_ptrs, int vertex_count) { int i, u[4], v[4]; @@ -1093,7 +1102,7 @@ static void do_triangle_enhanced(psx_gpu_struct *psx_gpu, if (!prepare_triangle(psx_gpu, vertexes, vertex_ptrs)) return; - if (!disable_main_render) + if (!psx_gpu->hack_disable_main) render_triangle_p(psx_gpu, vertex_ptrs, current_command); if (!check_enhanced_range(psx_gpu, vertex_ptrs[0]->x, vertex_ptrs[2]->x)) @@ -1194,10 +1203,11 @@ static void do_sprite_enhanced(psx_gpu_struct *psx_gpu, int x, int y, #endif u32 gpu_parse_enhanced(psx_gpu_struct *psx_gpu, u32 *list, u32 size, - u32 *last_command) + s32 *cpu_cycles_sum_out, s32 *cpu_cycles_last, u32 *last_command) { vertex_struct vertexes[4] __attribute__((aligned(16))) = {}; u32 current_command = 0, command_length; + u32 cpu_cycles_sum = 0, cpu_cycles = *cpu_cycles_last; u32 *list_start = list; u32 *list_end = list + (size / 4); @@ -1236,6 +1246,7 @@ u32 gpu_parse_enhanced(psx_gpu_struct *psx_gpu, u32 *list, u32 size, x &= ~0xF; width = ((width + 0xF) & ~0xF); + gput_sum(cpu_cycles_sum, cpu_cycles, gput_fill(width, height)); if (width == 0 || height == 0) break; @@ -1266,6 +1277,7 @@ u32 gpu_parse_enhanced(psx_gpu_struct *psx_gpu, u32 *list, u32 size, get_vertex_data_xy(2, 6); do_triangle_enhanced(psx_gpu, vertexes, current_command); + gput_sum(cpu_cycles_sum, cpu_cycles, gput_poly_base()); break; } @@ -1280,6 +1292,7 @@ u32 gpu_parse_enhanced(psx_gpu_struct *psx_gpu, u32 *list, u32 size, get_vertex_data_xy_uv(2, 10); do_triangle_enhanced(psx_gpu, vertexes, current_command); + gput_sum(cpu_cycles_sum, cpu_cycles, gput_poly_base_t()); break; } @@ -1293,6 +1306,7 @@ u32 gpu_parse_enhanced(psx_gpu_struct *psx_gpu, u32 *list, u32 size, get_vertex_data_xy(3, 8); do_quad_enhanced(psx_gpu, vertexes, current_command); + gput_sum(cpu_cycles_sum, cpu_cycles, gput_quad_base()); break; } @@ -1307,8 +1321,10 @@ u32 gpu_parse_enhanced(psx_gpu_struct *psx_gpu, u32 *list, u32 size, get_vertex_data_xy_uv(2, 10); get_vertex_data_xy_uv(3, 14); - uv_hack(vertexes, 4); + if (psx_gpu->hack_texture_adj) + uv_hack(vertexes, 4); do_quad_enhanced(psx_gpu, vertexes, current_command); + gput_sum(cpu_cycles_sum, cpu_cycles, gput_quad_base_t()); break; } @@ -1319,13 +1335,11 @@ u32 gpu_parse_enhanced(psx_gpu_struct *psx_gpu, u32 *list, u32 size, get_vertex_data_xy_rgb(2, 8); do_triangle_enhanced(psx_gpu, vertexes, current_command); + gput_sum(cpu_cycles_sum, cpu_cycles, gput_poly_base_g()); break; } - case 0x34: - case 0x35: - case 0x36: - case 0x37: + case 0x34 ... 0x37: { set_clut(psx_gpu, list_s16[5]); set_texture(psx_gpu, list_s16[11]); @@ -1335,13 +1349,11 @@ u32 gpu_parse_enhanced(psx_gpu_struct *psx_gpu, u32 *list, u32 size, get_vertex_data_xy_uv_rgb(2, 12); do_triangle_enhanced(psx_gpu, vertexes, current_command); + gput_sum(cpu_cycles_sum, cpu_cycles, gput_poly_base_gt()); break; } - case 0x38: - case 0x39: - case 0x3A: - case 0x3B: + case 0x38 ... 0x3B: { get_vertex_data_xy_rgb(0, 0); get_vertex_data_xy_rgb(1, 4); @@ -1349,13 +1361,11 @@ u32 gpu_parse_enhanced(psx_gpu_struct *psx_gpu, u32 *list, u32 size, get_vertex_data_xy_rgb(3, 12); do_quad_enhanced(psx_gpu, vertexes, current_command); + gput_sum(cpu_cycles_sum, cpu_cycles, gput_quad_base_g()); break; } - case 0x3C: - case 0x3D: - case 0x3E: - case 0x3F: + case 0x3C ... 0x3F: { set_clut(psx_gpu, list_s16[5]); set_texture(psx_gpu, list_s16[11]); @@ -1365,8 +1375,10 @@ u32 gpu_parse_enhanced(psx_gpu_struct *psx_gpu, u32 *list, u32 size, get_vertex_data_xy_uv_rgb(2, 12); get_vertex_data_xy_uv_rgb(3, 18); - uv_hack(vertexes, 4); + if (psx_gpu->hack_texture_adj) + uv_hack(vertexes, 4); do_quad_enhanced(psx_gpu, vertexes, current_command); + gput_sum(cpu_cycles_sum, cpu_cycles, gput_quad_base_gt()); break; } @@ -1380,6 +1392,7 @@ u32 gpu_parse_enhanced(psx_gpu_struct *psx_gpu, u32 *list, u32 size, render_line(psx_gpu, vertexes, current_command, list[0], 0); if (enhancement_enable(psx_gpu)) render_line(psx_gpu, vertexes, current_command, list[0], 1); + gput_sum(cpu_cycles_sum, cpu_cycles, gput_line(0)); break; } @@ -1404,6 +1417,7 @@ u32 gpu_parse_enhanced(psx_gpu_struct *psx_gpu, u32 *list, u32 size, render_line(psx_gpu, vertexes, current_command, list[0], 0); if (enhancement_enable(psx_gpu)) render_line(psx_gpu, vertexes, current_command, list[0], 1); + gput_sum(cpu_cycles_sum, cpu_cycles, gput_line(0)); list_position++; num_vertexes++; @@ -1440,6 +1454,7 @@ u32 gpu_parse_enhanced(psx_gpu_struct *psx_gpu, u32 *list, u32 size, render_line(psx_gpu, vertexes, current_command, 0, 0); if (enhancement_enable(psx_gpu)) render_line(psx_gpu, vertexes, current_command, 0, 1); + gput_sum(cpu_cycles_sum, cpu_cycles, gput_line(0)); break; } @@ -1473,6 +1488,7 @@ u32 gpu_parse_enhanced(psx_gpu_struct *psx_gpu, u32 *list, u32 size, render_line(psx_gpu, vertexes, current_command, 0, 0); if (enhancement_enable(psx_gpu)) render_line(psx_gpu, vertexes, current_command, 0, 1); + gput_sum(cpu_cycles_sum, cpu_cycles, gput_line(0)); list_position += 2; num_vertexes++; @@ -1496,13 +1512,18 @@ u32 gpu_parse_enhanced(psx_gpu_struct *psx_gpu, u32 *list, u32 size, { u32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x); u32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y); - u32 width = list_s16[4] & 0x3FF; - u32 height = list_s16[5] & 0x1FF; + s32 width = list_s16[4] & 0x3FF; + s32 height = list_s16[5] & 0x1FF; - render_sprite(psx_gpu, x, y, 0, 0, width, height, current_command, list[0]); + render_sprite(psx_gpu, x, y, 0, 0, &width, &height, + current_command, list[0]); + gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(width, height)); - if (check_enhanced_range(psx_gpu, x, x + width)) + if (check_enhanced_range(psx_gpu, x, x + width)) { + width = list_s16[4] & 0x3FF; + height = list_s16[5] & 0x1FF; do_sprite_enhanced(psx_gpu, x, y, 0, 0, width, height, list[0]); + } break; } @@ -1512,97 +1533,100 @@ u32 gpu_parse_enhanced(psx_gpu_struct *psx_gpu, u32 *list, u32 size, u32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y); u8 u = list_s16[4]; u8 v = list_s16[4] >> 8; - u32 width = list_s16[6] & 0x3FF; - u32 height = list_s16[7] & 0x1FF; + s32 width = list_s16[6] & 0x3FF; + s32 height = list_s16[7] & 0x1FF; set_clut(psx_gpu, list_s16[5]); - render_sprite(psx_gpu, x, y, u, v, width, height, - current_command, list[0]); + render_sprite(psx_gpu, x, y, u, v, + &width, &height, current_command, list[0]); + gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(width, height)); - if (check_enhanced_range(psx_gpu, x, x + width)) + if (check_enhanced_range(psx_gpu, x, x + width)) { + width = list_s16[6] & 0x3FF; + height = list_s16[7] & 0x1FF; do_sprite_enhanced(psx_gpu, x, y, u, v, width, height, list[0]); + } break; } - case 0x68: - case 0x69: - case 0x6A: - case 0x6B: + case 0x68 ... 0x6B: { s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x); s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y); + s32 width = 1, height = 1; - render_sprite(psx_gpu, x, y, 0, 0, 1, 1, current_command, list[0]); + render_sprite(psx_gpu, x, y, 0, 0, &width, &height, + current_command, list[0]); + gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(1, 1)); if (check_enhanced_range(psx_gpu, x, x + 1)) do_sprite_enhanced(psx_gpu, x, y, 0, 0, 1, 1, list[0]); break; } - case 0x70: - case 0x71: - case 0x72: - case 0x73: + case 0x70 ... 0x73: { s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x); s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y); + s32 width = 8, height = 8; - render_sprite(psx_gpu, x, y, 0, 0, 8, 8, current_command, list[0]); + render_sprite(psx_gpu, x, y, 0, 0, &width, &height, + current_command, list[0]); + gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(width, height)); if (check_enhanced_range(psx_gpu, x, x + 8)) do_sprite_enhanced(psx_gpu, x, y, 0, 0, 8, 8, list[0]); break; } - case 0x74: - case 0x75: - case 0x76: - case 0x77: + case 0x74 ... 0x77: { s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x); s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y); u8 u = list_s16[4]; u8 v = list_s16[4] >> 8; + s32 width = 8, height = 8; set_clut(psx_gpu, list_s16[5]); - render_sprite(psx_gpu, x, y, u, v, 8, 8, - current_command, list[0]); + render_sprite(psx_gpu, x, y, u, v, + &width, &height, current_command, list[0]); + gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(width, height)); if (check_enhanced_range(psx_gpu, x, x + 8)) do_sprite_enhanced(psx_gpu, x, y, u, v, 8, 8, list[0]); break; } - case 0x78: - case 0x79: - case 0x7A: - case 0x7B: + case 0x78 ... 0x7B: { s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x); s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y); + s32 width = 16, height = 16; - render_sprite(psx_gpu, x, y, 0, 0, 16, 16, current_command, list[0]); + render_sprite(psx_gpu, x, y, 0, 0, &width, &height, + current_command, list[0]); + gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(width, height)); if (check_enhanced_range(psx_gpu, x, x + 16)) do_sprite_enhanced(psx_gpu, x, y, 0, 0, 16, 16, list[0]); break; } - case 0x7C: - case 0x7D: - case 0x7E: - case 0x7F: + case 0x7C ... 0x7F: { s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x); s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y); u8 u = list_s16[4]; u8 v = list_s16[4] >> 8; + s32 width = 16, height = 16; set_clut(psx_gpu, list_s16[5]); - render_sprite(psx_gpu, x, y, u, v, 16, 16, current_command, list[0]); + render_sprite(psx_gpu, x, y, u, v, + &width, &height, current_command, list[0]); + gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(width, height)); if (check_enhanced_range(psx_gpu, x, x + 16)) do_sprite_enhanced(psx_gpu, x, y, u, v, 16, 16, list[0]); @@ -1759,8 +1783,9 @@ u32 gpu_parse_enhanced(psx_gpu_struct *psx_gpu, u32 *list, u32 size, enhancement_disable(); breakloop: - if (last_command != NULL) - *last_command = current_command; + *cpu_cycles_sum_out += cpu_cycles_sum; + *cpu_cycles_last = cpu_cycles; + *last_command = current_command; return list - list_start; } diff --git a/pcsx_rearmed/plugins/gpu_neon/psx_gpu_if.c b/pcsx_rearmed/plugins/gpu_neon/psx_gpu_if.c index 3dab827c..6e7e5fd7 100644 --- a/pcsx_rearmed/plugins/gpu_neon/psx_gpu_if.c +++ b/pcsx_rearmed/plugins/gpu_neon/psx_gpu_if.c @@ -38,7 +38,8 @@ sync_enhancement_buffers(int x, int y, int w, int h); static psx_gpu_struct egpu __attribute__((aligned(256))); -int do_cmd_list(uint32_t *list, int count, int *last_cmd) +int do_cmd_list(uint32_t *list, int count, + int *cycles_sum, int *cycles_last, int *last_cmd) { int ret; @@ -48,9 +49,11 @@ int do_cmd_list(uint32_t *list, int count, int *last_cmd) #endif if (gpu.state.enhancement_active) - ret = gpu_parse_enhanced(&egpu, list, count * 4, (u32 *)last_cmd); + ret = gpu_parse_enhanced(&egpu, list, count * 4, + cycles_sum, cycles_last, (u32 *)last_cmd); else - ret = gpu_parse(&egpu, list, count * 4, (u32 *)last_cmd); + ret = gpu_parse(&egpu, list, count * 4, + cycles_sum, cycles_last, (u32 *)last_cmd); #if defined(__arm__) && defined(NEON_BUILD) && !defined(SIMD_BUILD) __asm__ __volatile__("":::"q4","q5","q6","q7"); @@ -128,6 +131,8 @@ sync_enhancement_buffers(int x, int y, int w, int h) // due to intersection stuff, see the update_enhancement_buf_scanouts() mess int s_w = max(gpu.screen.hres, gpu.screen.w); int s_h = gpu.screen.vres; + if (gpu.screen.y < 0) + s_h -= gpu.screen.y; s_w = min(s_w, 512); for (i = 0; i < ARRAY_SIZE(egpu.enhancement_scanouts); i++) { const struct psx_gpu_scanout *s = &egpu.enhancement_scanouts[i]; @@ -142,6 +147,9 @@ sync_enhancement_buffers(int x, int y, int w, int h) x2 = min(right, s->x + s_w); y1 = max(y, s->y); y2 = min(bottom, s->y + s_h); + // 16-byte align for the asm version + x2 += x1 & 7; + x1 &= ~7; scale2x_tiles8(dst + y1 * 1024*2 + x1 * 2, src + y1 * 1024 + x1, (x2 - x1 + 7) / 8u, y2 - y1); } @@ -149,7 +157,9 @@ sync_enhancement_buffers(int x, int y, int w, int h) void renderer_sync_ecmds(uint32_t *ecmds) { - gpu_parse(&egpu, ecmds + 1, 6 * 4, NULL); + s32 dummy0 = 0; + u32 dummy1 = 0; + gpu_parse(&egpu, ecmds + 1, 6 * 4, &dummy0, &dummy0, &dummy1); } void renderer_update_caches(int x, int y, int w, int h, int state_changed) @@ -158,10 +168,13 @@ void renderer_update_caches(int x, int y, int w, int h, int state_changed) if (gpu.state.enhancement_active) { if (state_changed) { + int vres = gpu.screen.vres; + if (gpu.screen.y < 0) + vres -= gpu.screen.y; memset(egpu.enhancement_scanouts, 0, sizeof(egpu.enhancement_scanouts)); egpu.enhancement_scanout_eselect = 0; update_enhancement_buf_scanouts(&egpu, - gpu.screen.src_x, gpu.screen.src_y, gpu.screen.hres, gpu.screen.vres); + gpu.screen.src_x, gpu.screen.src_y, gpu.screen.hres, vres); return; } sync_enhancement_buffers(x, y, w, h); @@ -189,10 +202,13 @@ void renderer_notify_res_change(void) void renderer_notify_scanout_change(int x, int y) { + int vres = gpu.screen.vres; if (!gpu.state.enhancement_active || !egpu.enhancement_buf_ptr) return; - update_enhancement_buf_scanouts(&egpu, x, y, gpu.screen.hres, gpu.screen.vres); + if (gpu.screen.y < 0) + vres -= gpu.screen.y; + update_enhancement_buf_scanouts(&egpu, x, y, gpu.screen.hres, vres); } #include "../../frontend/plugin_lib.h" @@ -219,7 +235,8 @@ void renderer_set_config(const struct rearmed_cbs *cbs) egpu.dither_table[3] = dither_table_row(3, -1, 2, -2); } - disable_main_render = cbs->gpu_neon.enhancement_no_main; + egpu.hack_disable_main = cbs->gpu_neon.enhancement_no_main; + egpu.hack_texture_adj = cbs->gpu_neon.enhancement_tex_adj; if (gpu.state.enhancement_enable) { if (gpu.mmap != NULL && egpu.enhancement_buf_ptr == NULL) map_enhancement_buffer(); diff --git a/pcsx_rearmed/plugins/gpu_unai/gpu_raster_image.h b/pcsx_rearmed/plugins/gpu_unai/gpu_raster_image.h index 909ca390..7c9eb4d9 100644 --- a/pcsx_rearmed/plugins/gpu_unai/gpu_raster_image.h +++ b/pcsx_rearmed/plugins/gpu_unai/gpu_raster_image.h @@ -160,7 +160,7 @@ void gpuClearImage(PtrUnion packet) x0 = le16_to_s16(packet.U2[2]); y0 = le16_to_s16(packet.U2[3]); w0 = le16_to_s16(packet.U2[4]) & 0x3ff; - h0 = le16_to_s16(packet.U2[5]) & 0x3ff; + h0 = le16_to_s16(packet.U2[5]) & 0x1ff; w0 += x0; if (x0 < 0) x0 = 0; diff --git a/pcsx_rearmed/plugins/gpu_unai/gpu_raster_sprite.h b/pcsx_rearmed/plugins/gpu_unai/gpu_raster_sprite.h index ea4e82f2..6909f4f8 100644 --- a/pcsx_rearmed/plugins/gpu_unai/gpu_raster_sprite.h +++ b/pcsx_rearmed/plugins/gpu_unai/gpu_raster_sprite.h @@ -24,7 +24,7 @@ /////////////////////////////////////////////////////////////////////////////// // GPU internal sprite drawing functions -void gpuDrawS(PtrUnion packet, const PS gpuSpriteSpanDriver) +void gpuDrawS(PtrUnion packet, const PS gpuSpriteSpanDriver, s32 *w_out, s32 *h_out) { s32 x0, x1, y0, y1; u32 u0, v0; @@ -58,6 +58,8 @@ void gpuDrawS(PtrUnion packet, const PS gpuSpriteSpanDriver) if (x1 > xmax) x1 = xmax; x1 -= x0; if (x1 <= 0) return; + *w_out = x1; + *h_out = y1 - y0; gpu_unai.r5 = packet.U1[0] >> 3; gpu_unai.g5 = packet.U1[1] >> 3; @@ -87,7 +89,7 @@ void gpuDrawS(PtrUnion packet, const PS gpuSpriteSpanDriver) #include "gpu_arm.h" /* Notaz 4bit sprites optimization */ -void gpuDrawS16(PtrUnion packet) +void gpuDrawS16(PtrUnion packet, s32 *w_out, s32 *h_out) { s32 x0, y0; s32 u0, v0; @@ -110,7 +112,7 @@ void gpuDrawS16(PtrUnion packet) ((u0 | v0) & 15) || !(gpu_unai.TextureWindow[2] & gpu_unai.TextureWindow[3] & 8)) { // send corner cases to general handler packet.U4[3] = u32_to_le32(0x00100010); - gpuDrawS(packet, gpuSpriteSpanFn<0x20>); + gpuDrawS(packet, gpuSpriteSpanFn<0x20>, w_out, h_out); return; } @@ -123,12 +125,14 @@ void gpuDrawS16(PtrUnion packet) } else if (ymax - y0 < 16) h = ymax - y0; + *w_out = 16; + *h_out = h; draw_spr16_full(&gpu_unai.vram[FRAME_OFFSET(x0, y0)], &gpu_unai.TBA[FRAME_OFFSET(u0/4, v0)], gpu_unai.CBA, h); } #endif // __arm__ -void gpuDrawT(PtrUnion packet, const PT gpuTileSpanDriver) +void gpuDrawT(PtrUnion packet, const PT gpuTileSpanDriver, s32 *w_out, s32 *h_out) { s32 x0, x1, y0, y1; @@ -153,6 +157,8 @@ void gpuDrawT(PtrUnion packet, const PT gpuTileSpanDriver) if (x1 > xmax) x1 = xmax; x1 -= x0; if (x1 <= 0) return; + *w_out = x1; + *h_out = y1 - y0; const u16 Data = GPU_RGB16(le32_to_u32(packet.U4[0])); le16_t *Pixel = &gpu_unai.vram[FRAME_OFFSET(x0, y0)]; diff --git a/pcsx_rearmed/plugins/gpu_unai/gpulib_if.cpp b/pcsx_rearmed/plugins/gpu_unai/gpulib_if.cpp index 20794316..6816e2bd 100644 --- a/pcsx_rearmed/plugins/gpu_unai/gpulib_if.cpp +++ b/pcsx_rearmed/plugins/gpu_unai/gpulib_if.cpp @@ -390,12 +390,15 @@ static void gpuGP0Cmd_0xEx(gpu_unai_t &gpu_unai, u32 cmd_word) } #endif +#include "../gpulib/gpu_timing.h" extern const unsigned char cmd_lengths[256]; -int do_cmd_list(u32 *_list, int list_len, int *last_cmd) +int do_cmd_list(u32 *list_, int list_len, + int *cycles_sum_out, int *cycles_last, int *last_cmd) { + int cpu_cycles_sum = 0, cpu_cycles = *cycles_last; u32 cmd = 0, len, i; - le32_t *list = (le32_t *)_list; + le32_t *list = (le32_t *)list_; le32_t *list_start = list; le32_t *list_end = list + list_len; @@ -430,6 +433,8 @@ int do_cmd_list(u32 *_list, int list_len, int *last_cmd) { case 0x02: gpuClearImage(packet); + gput_sum(cpu_cycles_sum, cpu_cycles, + gput_fill(le16_to_s16(packet.U2[4]) & 0x3ff, le16_to_s16(packet.U2[5]) & 0x1ff)); break; case 0x20: @@ -442,6 +447,7 @@ int do_cmd_list(u32 *_list, int list_len, int *last_cmd) gpu_unai.Masking | Blending | gpu_unai.PixelMSB ]; gpuDrawPolyF(packet, driver, false); + gput_sum(cpu_cycles_sum, cpu_cycles, gput_poly_base()); } break; case 0x24: @@ -466,6 +472,7 @@ int do_cmd_list(u32 *_list, int list_len, int *last_cmd) PP driver = gpuPolySpanDrivers[driver_idx]; gpuDrawPolyFT(packet, driver, false); + gput_sum(cpu_cycles_sum, cpu_cycles, gput_poly_base_t()); } break; case 0x28: @@ -478,6 +485,7 @@ int do_cmd_list(u32 *_list, int list_len, int *last_cmd) gpu_unai.Masking | Blending | gpu_unai.PixelMSB ]; gpuDrawPolyF(packet, driver, true); // is_quad = true + gput_sum(cpu_cycles_sum, cpu_cycles, gput_quad_base()); } break; case 0x2C: @@ -502,6 +510,7 @@ int do_cmd_list(u32 *_list, int list_len, int *last_cmd) PP driver = gpuPolySpanDrivers[driver_idx]; gpuDrawPolyFT(packet, driver, true); // is_quad = true + gput_sum(cpu_cycles_sum, cpu_cycles, gput_quad_base_t()); } break; case 0x30: @@ -519,6 +528,7 @@ int do_cmd_list(u32 *_list, int list_len, int *last_cmd) gpu_unai.Masking | Blending | 129 | gpu_unai.PixelMSB ]; gpuDrawPolyG(packet, driver, false); + gput_sum(cpu_cycles_sum, cpu_cycles, gput_poly_base_g()); } break; case 0x34: @@ -534,6 +544,7 @@ int do_cmd_list(u32 *_list, int list_len, int *last_cmd) gpu_unai.Masking | Blending | ((Lighting)?129:0) | gpu_unai.PixelMSB ]; gpuDrawPolyGT(packet, driver, false); + gput_sum(cpu_cycles_sum, cpu_cycles, gput_poly_base_gt()); } break; case 0x38: @@ -548,6 +559,7 @@ int do_cmd_list(u32 *_list, int list_len, int *last_cmd) gpu_unai.Masking | Blending | 129 | gpu_unai.PixelMSB ]; gpuDrawPolyG(packet, driver, true); // is_quad = true + gput_sum(cpu_cycles_sum, cpu_cycles, gput_quad_base_g()); } break; case 0x3C: @@ -563,6 +575,7 @@ int do_cmd_list(u32 *_list, int list_len, int *last_cmd) gpu_unai.Masking | Blending | ((Lighting)?129:0) | gpu_unai.PixelMSB ]; gpuDrawPolyGT(packet, driver, true); // is_quad = true + gput_sum(cpu_cycles_sum, cpu_cycles, gput_quad_base_gt()); } break; case 0x40: @@ -573,6 +586,7 @@ int do_cmd_list(u32 *_list, int list_len, int *last_cmd) u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1; PSD driver = gpuPixelSpanDrivers[driver_idx]; gpuDrawLineF(packet, driver); + gput_sum(cpu_cycles_sum, cpu_cycles, gput_line(0)); } break; case 0x48 ... 0x4F: { // Monochrome line strip @@ -589,6 +603,7 @@ int do_cmd_list(u32 *_list, int list_len, int *last_cmd) gpu_unai.PacketBuffer.U4[1] = gpu_unai.PacketBuffer.U4[2]; gpu_unai.PacketBuffer.U4[2] = *list_position++; gpuDrawLineF(packet, driver); + gput_sum(cpu_cycles_sum, cpu_cycles, gput_line(0)); num_vertexes++; if(list_position >= list_end) { @@ -612,6 +627,7 @@ int do_cmd_list(u32 *_list, int list_len, int *last_cmd) driver_idx |= (1 << 5); PSD driver = gpuPixelSpanDrivers[driver_idx]; gpuDrawLineG(packet, driver); + gput_sum(cpu_cycles_sum, cpu_cycles, gput_line(0)); } break; case 0x58 ... 0x5F: { // Gouraud-shaded line strip @@ -632,6 +648,7 @@ int do_cmd_list(u32 *_list, int list_len, int *last_cmd) gpu_unai.PacketBuffer.U4[2] = *list_position++; gpu_unai.PacketBuffer.U4[3] = *list_position++; gpuDrawLineG(packet, driver); + gput_sum(cpu_cycles_sum, cpu_cycles, gput_line(0)); num_vertexes++; if(list_position >= list_end) { @@ -650,7 +667,9 @@ int do_cmd_list(u32 *_list, int list_len, int *last_cmd) case 0x62: case 0x63: { // Monochrome rectangle (variable size) PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1]; - gpuDrawT(packet, driver); + s32 w = 0, h = 0; + gpuDrawT(packet, driver, &w, &h); + gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(w, h)); } break; case 0x64: @@ -659,6 +678,7 @@ int do_cmd_list(u32 *_list, int list_len, int *last_cmd) case 0x67: { // Textured rectangle (variable size) gpuSetCLUT (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16); u32 driver_idx = Blending_Mode | gpu_unai.TEXT_MODE | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>1); + s32 w = 0, h = 0; //senquack - Only color 808080h-878787h allows skipping lighting calculation: // This fixes Silent Hill running animation on loading screens: @@ -677,7 +697,8 @@ int do_cmd_list(u32 *_list, int list_len, int *last_cmd) if ((le32_raw(gpu_unai.PacketBuffer.U4[0]) & HTOLE32(0xF8F8F8)) != HTOLE32(0x808080)) driver_idx |= Lighting; PS driver = gpuSpriteSpanDrivers[driver_idx]; - gpuDrawS(packet, driver); + gpuDrawS(packet, driver, &w, &h); + gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(w, h)); } break; case 0x68: @@ -686,7 +707,9 @@ int do_cmd_list(u32 *_list, int list_len, int *last_cmd) case 0x6B: { // Monochrome rectangle (1x1 dot) gpu_unai.PacketBuffer.U4[2] = u32_to_le32(0x00010001); PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1]; - gpuDrawT(packet, driver); + s32 w = 0, h = 0; + gpuDrawT(packet, driver, &w, &h); + gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(1, 1)); } break; case 0x70: @@ -695,7 +718,9 @@ int do_cmd_list(u32 *_list, int list_len, int *last_cmd) case 0x73: { // Monochrome rectangle (8x8) gpu_unai.PacketBuffer.U4[2] = u32_to_le32(0x00080008); PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1]; - gpuDrawT(packet, driver); + s32 w = 0, h = 0; + gpuDrawT(packet, driver, &w, &h); + gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(w, h)); } break; case 0x74: @@ -705,6 +730,7 @@ int do_cmd_list(u32 *_list, int list_len, int *last_cmd) gpu_unai.PacketBuffer.U4[3] = u32_to_le32(0x00080008); gpuSetCLUT (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16); u32 driver_idx = Blending_Mode | gpu_unai.TEXT_MODE | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>1); + s32 w = 0, h = 0; //senquack - Only color 808080h-878787h allows skipping lighting calculation: //if ((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F)) @@ -712,7 +738,8 @@ int do_cmd_list(u32 *_list, int list_len, int *last_cmd) if ((le32_raw(gpu_unai.PacketBuffer.U4[0]) & HTOLE32(0xF8F8F8)) != HTOLE32(0x808080)) driver_idx |= Lighting; PS driver = gpuSpriteSpanDrivers[driver_idx]; - gpuDrawS(packet, driver); + gpuDrawS(packet, driver, &w, &h); + gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(w, h)); } break; case 0x78: @@ -721,7 +748,9 @@ int do_cmd_list(u32 *_list, int list_len, int *last_cmd) case 0x7B: { // Monochrome rectangle (16x16) gpu_unai.PacketBuffer.U4[2] = u32_to_le32(0x00100010); PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1]; - gpuDrawT(packet, driver); + s32 w = 0, h = 0; + gpuDrawT(packet, driver, &w, &h); + gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(w, h)); } break; case 0x7C: @@ -729,8 +758,10 @@ int do_cmd_list(u32 *_list, int list_len, int *last_cmd) #ifdef __arm__ if ((gpu_unai.GPU_GP1 & 0x180) == 0 && (gpu_unai.Masking | gpu_unai.PixelMSB) == 0) { - gpuSetCLUT (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16); - gpuDrawS16(packet); + s32 w = 0, h = 0; + gpuSetCLUT(le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16); + gpuDrawS16(packet, &w, &h); + gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(w, h)); break; } // fallthrough @@ -740,13 +771,15 @@ int do_cmd_list(u32 *_list, int list_len, int *last_cmd) gpu_unai.PacketBuffer.U4[3] = u32_to_le32(0x00100010); gpuSetCLUT (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16); u32 driver_idx = Blending_Mode | gpu_unai.TEXT_MODE | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>1); + s32 w = 0, h = 0; //senquack - Only color 808080h-878787h allows skipping lighting calculation: //if ((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F)) // Strip lower 3 bits of each color and determine if lighting should be used: if ((le32_raw(gpu_unai.PacketBuffer.U4[0]) & HTOLE32(0xF8F8F8)) != HTOLE32(0x808080)) driver_idx |= Lighting; PS driver = gpuSpriteSpanDrivers[driver_idx]; - gpuDrawS(packet, driver); + gpuDrawS(packet, driver, &w, &h); + gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(w, h)); } break; #ifdef TEST @@ -766,6 +799,7 @@ int do_cmd_list(u32 *_list, int list_len, int *last_cmd) case 0xC0: break; #else + case 0x1F: // irq? case 0x80 ... 0x9F: // vid -> vid case 0xA0 ... 0xBF: // sys -> vid case 0xC0 ... 0xDF: // vid -> sys @@ -782,6 +816,8 @@ int do_cmd_list(u32 *_list, int list_len, int *last_cmd) gpu.ex_regs[1] &= ~0x1ff; gpu.ex_regs[1] |= gpu_unai.GPU_GP1 & 0x1ff; + *cycles_sum_out += cpu_cycles_sum; + *cycles_last = cpu_cycles; *last_cmd = cmd; return list - list_start; } @@ -789,7 +825,7 @@ int do_cmd_list(u32 *_list, int list_len, int *last_cmd) void renderer_sync_ecmds(u32 *ecmds) { int dummy; - do_cmd_list(&ecmds[1], 6, &dummy); + do_cmd_list(&ecmds[1], 6, &dummy, &dummy, &dummy); } void renderer_update_caches(int x, int y, int w, int h, int state_changed) diff --git a/pcsx_rearmed/plugins/gpulib/gpu.c b/pcsx_rearmed/plugins/gpulib/gpu.c index 24fbf3bf..c0603e08 100644 --- a/pcsx_rearmed/plugins/gpulib/gpu.c +++ b/pcsx_rearmed/plugins/gpulib/gpu.c @@ -14,6 +14,7 @@ #include /* for calloc */ #include "gpu.h" +#include "gpu_timing.h" #include "../../libpcsxcore/gpu.h" // meh #include "../../frontend/plugin_lib.h" @@ -35,15 +36,16 @@ struct psx_gpu gpu; -static noinline int do_cmd_buffer(uint32_t *data, int count); +static noinline int do_cmd_buffer(uint32_t *data, int count, + int *cycles_sum, int *cycles_last); static void finish_vram_transfer(int is_read); static noinline void do_cmd_reset(void) { + int dummy = 0; renderer_sync(); - if (unlikely(gpu.cmd_len > 0)) - do_cmd_buffer(gpu.cmd_buffer, gpu.cmd_len); + do_cmd_buffer(gpu.cmd_buffer, gpu.cmd_len, &dummy, &dummy); gpu.cmd_len = 0; if (unlikely(gpu.dma.h > 0)) @@ -180,8 +182,8 @@ static noinline void decide_frameskip(void) gpu.frameskip.active = 0; if (!gpu.frameskip.active && gpu.frameskip.pending_fill[0] != 0) { - int dummy; - do_cmd_list(gpu.frameskip.pending_fill, 3, &dummy); + int dummy = 0; + do_cmd_list(gpu.frameskip.pending_fill, 3, &dummy, &dummy, &dummy); gpu.frameskip.pending_fill[0] = 0; } } @@ -517,7 +519,7 @@ static void finish_vram_transfer(int is_read) gpu.gpu_state_change(PGS_VRAM_TRANSFER_END); } -static void do_vram_copy(const uint32_t *params) +static void do_vram_copy(const uint32_t *params, int *cpu_cycles) { const uint32_t sx = LE32TOH(params[0]) & 0x3FF; const uint32_t sy = (LE32TOH(params[0]) >> 16) & 0x1FF; @@ -529,6 +531,7 @@ static void do_vram_copy(const uint32_t *params) uint16_t lbuf[128]; uint32_t x, y; + *cpu_cycles += gput_copy(w, h); if (sx == dx && sy == dy && msb == 0) return; @@ -564,7 +567,7 @@ static void do_vram_copy(const uint32_t *params) static noinline int do_cmd_list_skip(uint32_t *data, int count, int *last_cmd) { - int cmd = 0, pos = 0, len, dummy, v; + int cmd = 0, pos = 0, len, dummy = 0, v; int skip = 1; gpu.frameskip.pending_fill[0] = 0; @@ -578,7 +581,7 @@ static noinline int do_cmd_list_skip(uint32_t *data, int count, int *last_cmd) case 0x02: if ((LE32TOH(list[2]) & 0x3ff) > gpu.screen.w || ((LE32TOH(list[2]) >> 16) & 0x1ff) > gpu.screen.h) // clearing something large, don't skip - do_cmd_list(list, 3, &dummy); + do_cmd_list(list, 3, &dummy, &dummy, &dummy); else memcpy(gpu.frameskip.pending_fill, list, 3 * 4); break; @@ -628,7 +631,8 @@ static noinline int do_cmd_list_skip(uint32_t *data, int count, int *last_cmd) return pos; } -static noinline int do_cmd_buffer(uint32_t *data, int count) +static noinline int do_cmd_buffer(uint32_t *data, int count, + int *cycles_sum, int *cycles_last) { int cmd, pos; uint32_t old_e3 = gpu.ex_regs[3]; @@ -662,17 +666,25 @@ static noinline int do_cmd_buffer(uint32_t *data, int count) cmd = -1; // incomplete cmd, can't consume yet break; } - do_vram_copy(data + pos + 1); + renderer_sync(); + *cycles_sum += *cycles_last; + *cycles_last = 0; + do_vram_copy(data + pos + 1, cycles_last); vram_dirty = 1; pos += 4; continue; } + else if (cmd == 0x1f) { + log_anomaly("irq1?\n"); + pos++; + continue; + } // 0xex cmds might affect frameskip.allow, so pass to do_cmd_list_skip if (gpu.frameskip.active && (gpu.frameskip.allow || ((LE32TOH(data[pos]) >> 24) & 0xf0) == 0xe0)) pos += do_cmd_list_skip(data + pos, count - pos, &cmd); else { - pos += do_cmd_list(data + pos, count - pos, &cmd); + pos += do_cmd_list(data + pos, count - pos, cycles_sum, cycles_last, &cmd); vram_dirty = 1; } @@ -695,7 +707,8 @@ static noinline int do_cmd_buffer(uint32_t *data, int count) static noinline void flush_cmd_buffer(void) { - int left = do_cmd_buffer(gpu.cmd_buffer, gpu.cmd_len); + int dummy = 0, left; + left = do_cmd_buffer(gpu.cmd_buffer, gpu.cmd_len, &dummy, &dummy); if (left > 0) memmove(gpu.cmd_buffer, gpu.cmd_buffer + gpu.cmd_len - left, left * 4); if (left != gpu.cmd_len) { @@ -707,14 +720,14 @@ static noinline void flush_cmd_buffer(void) void GPUwriteDataMem(uint32_t *mem, int count) { - int left; + int dummy = 0, left; log_io("gpu_dma_write %p %d\n", mem, count); if (unlikely(gpu.cmd_len > 0)) flush_cmd_buffer(); - left = do_cmd_buffer(mem, count); + left = do_cmd_buffer(mem, count, &dummy, &dummy); if (left) log_anomaly("GPUwriteDataMem: discarded %d/%d words\n", left, count); } @@ -727,11 +740,13 @@ void GPUwriteData(uint32_t data) flush_cmd_buffer(); } -long GPUdmaChain(uint32_t *rambase, uint32_t start_addr, uint32_t *progress_addr) +long GPUdmaChain(uint32_t *rambase, uint32_t start_addr, + uint32_t *progress_addr, int32_t *cycles_last_cmd) { - uint32_t addr, *list, ld_addr = 0; - int len, left, count; - long cpu_cycles = 0; + uint32_t addr, *list, ld_addr; + int len, left, count, ld_count = 32; + int cpu_cycles_sum = 0; + int cpu_cycles_last = 0; preload(rambase + (start_addr & 0x1fffff) / 4); @@ -739,7 +754,7 @@ long GPUdmaChain(uint32_t *rambase, uint32_t start_addr, uint32_t *progress_addr flush_cmd_buffer(); log_io("gpu_dma_chain\n"); - addr = start_addr & 0xffffff; + addr = ld_addr = start_addr & 0xffffff; for (count = 0; (addr & 0x800000) == 0; count++) { list = rambase + (addr & 0x1fffff) / 4; @@ -747,12 +762,12 @@ long GPUdmaChain(uint32_t *rambase, uint32_t start_addr, uint32_t *progress_addr addr = LE32TOH(list[0]) & 0xffffff; preload(rambase + (addr & 0x1fffff) / 4); - cpu_cycles += 10; + cpu_cycles_sum += 10; if (len > 0) - cpu_cycles += 5 + len; + cpu_cycles_sum += 5 + len; - log_io(".chain %08lx #%d+%d\n", - (long)(list - rambase) * 4, len, gpu.cmd_len); + log_io(".chain %08lx #%d+%d %u+%u\n", + (long)(list - rambase) * 4, len, gpu.cmd_len, cpu_cycles_sum, cpu_cycles_last); if (unlikely(gpu.cmd_len > 0)) { if (gpu.cmd_len + len > ARRAY_SIZE(gpu.cmd_buffer)) { log_anomaly("cmd_buffer overflow, likely garbage commands\n"); @@ -765,7 +780,7 @@ long GPUdmaChain(uint32_t *rambase, uint32_t start_addr, uint32_t *progress_addr } if (len) { - left = do_cmd_buffer(list + 1, len); + left = do_cmd_buffer(list + 1, len, &cpu_cycles_sum, &cpu_cycles_last); if (left) { memcpy(gpu.cmd_buffer, list + 1 + len - left, left * 4); gpu.cmd_len = left; @@ -777,37 +792,24 @@ long GPUdmaChain(uint32_t *rambase, uint32_t start_addr, uint32_t *progress_addr *progress_addr = addr; break; } - #define LD_THRESHOLD (8*1024) - if (count >= LD_THRESHOLD) { - if (count == LD_THRESHOLD) { - ld_addr = addr; - continue; - } - - // loop detection marker - // (bit23 set causes DMA error on real machine, so - // unlikely to be ever set by the game) - list[0] |= HTOLE32(0x800000); + if (addr == ld_addr) { + log_anomaly("GPUdmaChain: loop @ %08x, cnt=%u\n", addr, count); + break; } - } - - if (ld_addr != 0) { - // remove loop detection markers - count -= LD_THRESHOLD + 2; - addr = ld_addr & 0x1fffff; - while (count-- > 0) { - list = rambase + addr / 4; - addr = LE32TOH(list[0]) & 0x1fffff; - list[0] &= HTOLE32(~0x800000); + if (count == ld_count) { + ld_addr = addr; + ld_count *= 2; } } + //printf(" -> %d %d\n", cpu_cycles_sum, cpu_cycles_last); gpu.state.last_list.frame = *gpu.state.frame_count; gpu.state.last_list.hcnt = *gpu.state.hcnt; - gpu.state.last_list.cycles = cpu_cycles; + gpu.state.last_list.cycles = cpu_cycles_sum + cpu_cycles_last; gpu.state.last_list.addr = start_addr; - return cpu_cycles; + *cycles_last_cmd = cpu_cycles_last; + return cpu_cycles_sum; } void GPUreadDataMem(uint32_t *mem, int count) diff --git a/pcsx_rearmed/plugins/gpulib/gpu.h b/pcsx_rearmed/plugins/gpulib/gpu.h index 553afbdb..7625c412 100644 --- a/pcsx_rearmed/plugins/gpulib/gpu.h +++ b/pcsx_rearmed/plugins/gpulib/gpu.h @@ -122,7 +122,8 @@ extern struct psx_gpu gpu; extern const unsigned char cmd_lengths[256]; -int do_cmd_list(uint32_t *list, int count, int *last_cmd); +int do_cmd_list(uint32_t *list, int count, + int *cycles_sum, int *cycles_last, int *last_cmd); struct rearmed_cbs; @@ -150,7 +151,8 @@ struct GPUFreeze; long GPUinit(void); long GPUshutdown(void); void GPUwriteDataMem(uint32_t *mem, int count); -long GPUdmaChain(uint32_t *rambase, uint32_t addr, uint32_t *progress_addr); +long GPUdmaChain(uint32_t *rambase, uint32_t addr, + uint32_t *progress_addr, int32_t *cycles_last_cmd); void GPUwriteData(uint32_t data); void GPUreadDataMem(uint32_t *mem, int count); uint32_t GPUreadData(void); diff --git a/pcsx_rearmed/plugins/gpulib/gpu_timing.h b/pcsx_rearmed/plugins/gpulib/gpu_timing.h new file mode 100644 index 00000000..9991fd80 --- /dev/null +++ b/pcsx_rearmed/plugins/gpulib/gpu_timing.h @@ -0,0 +1,19 @@ + +// very conservative and wrong +#define gput_fill(w, h) (23 + (4 + (w) / 16u) * (h)) +#define gput_copy(w, h) ((w) * (h)) +#define gput_poly_base() (23) +#define gput_poly_base_t() (gput_poly_base() + 90) +#define gput_poly_base_g() (gput_poly_base() + 144) +#define gput_poly_base_gt() (gput_poly_base() + 225) +#define gput_quad_base() gput_poly_base() +#define gput_quad_base_t() gput_poly_base_t() +#define gput_quad_base_g() gput_poly_base_g() +#define gput_quad_base_gt() gput_poly_base_gt() +#define gput_line(k) (8 + (k)) +#define gput_sprite(w, h) (8 + ((w) / 2u) * (h)) + +// sort of a workaround for lack of proper fifo emulation +#define gput_sum(sum, cnt, new_cycles) do { \ + sum += cnt; cnt = new_cycles; \ +} while (0) diff --git a/pcsx_rearmed/plugins/gpulib/gpulib_thread_if.c b/pcsx_rearmed/plugins/gpulib/gpulib_thread_if.c index c18a6f60..107ffd35 100644 --- a/pcsx_rearmed/plugins/gpulib/gpulib_thread_if.c +++ b/pcsx_rearmed/plugins/gpulib/gpulib_thread_if.c @@ -23,6 +23,8 @@ #include #include "../gpulib/gpu.h" #include "../../frontend/plugin_lib.h" +#include "gpu.h" +#include "gpu_timing.h" #include "gpulib_thread_if.h" #define FALSE 0 @@ -74,7 +76,7 @@ static void *video_thread_main(void *arg) { #endif /* _3DS */ while(1) { - int result, last_cmd, start, end; + int result, cycles_dummy = 0, last_cmd, start, end; video_thread_queue *queue; pthread_mutex_lock(&thread->queue_lock); @@ -95,8 +97,8 @@ static void *video_thread_main(void *arg) { for (i = start; i < end; i++) { cmd = &queue->queue[i]; - result = real_do_cmd_list(cmd->cmd_list, cmd->count, &last_cmd); - + result = real_do_cmd_list(cmd->cmd_list, cmd->count, + &cycles_dummy, &cycles_dummy, &last_cmd); if (result != cmd->count) { fprintf(stderr, "Processed wrong cmd count: expected %d, got %d\n", cmd->count, result); } @@ -293,41 +295,99 @@ static void video_thread_queue_cmd(uint32_t *list, int count, int last_cmd) { /* Slice off just the part of the list that can be handled async, and * update ex_regs. */ -static int scan_cmd_list(uint32_t *data, int count, int *last_cmd) +static int scan_cmd_list(uint32_t *data, int count, + int *cycles_sum_out, int *cycles_last, int *last_cmd) { + int cpu_cycles_sum = 0, cpu_cycles = *cycles_last; int cmd = 0, pos = 0, len, v; while (pos < count) { uint32_t *list = data + pos; - cmd = list[0] >> 24; + short *slist = (void *)list; + cmd = LE32TOH(list[0]) >> 24; len = 1 + cmd_lengths[cmd]; switch (cmd) { case 0x02: + gput_sum(cpu_cycles_sum, cpu_cycles, + gput_fill(LE16TOH(slist[4]) & 0x3ff, + LE16TOH(slist[5]) & 0x1ff)); + break; + case 0x20 ... 0x23: + gput_sum(cpu_cycles_sum, cpu_cycles, gput_poly_base()); break; case 0x24 ... 0x27: + gput_sum(cpu_cycles_sum, cpu_cycles, gput_poly_base_t()); + gpu.ex_regs[1] &= ~0x1ff; + gpu.ex_regs[1] |= LE32TOH(list[4]) & 0x1ff; + break; + case 0x28 ... 0x2b: + gput_sum(cpu_cycles_sum, cpu_cycles, gput_quad_base()); + break; case 0x2c ... 0x2f: + gput_sum(cpu_cycles_sum, cpu_cycles, gput_quad_base_t()); + gpu.ex_regs[1] &= ~0x1ff; + gpu.ex_regs[1] |= LE32TOH(list[4]) & 0x1ff; + break; + case 0x30 ... 0x33: + gput_sum(cpu_cycles_sum, cpu_cycles, gput_poly_base_g()); + break; case 0x34 ... 0x37: + gput_sum(cpu_cycles_sum, cpu_cycles, gput_poly_base_gt()); + gpu.ex_regs[1] &= ~0x1ff; + gpu.ex_regs[1] |= LE32TOH(list[5]) & 0x1ff; + break; + case 0x38 ... 0x3b: + gput_sum(cpu_cycles_sum, cpu_cycles, gput_quad_base_g()); + break; case 0x3c ... 0x3f: + gput_sum(cpu_cycles_sum, cpu_cycles, gput_quad_base_gt()); gpu.ex_regs[1] &= ~0x1ff; - gpu.ex_regs[1] |= list[4 + ((cmd >> 4) & 1)] & 0x1ff; + gpu.ex_regs[1] |= LE32TOH(list[5]) & 0x1ff; + break; + case 0x40 ... 0x47: + gput_sum(cpu_cycles_sum, cpu_cycles, gput_line(0)); break; case 0x48 ... 0x4F: for (v = 3; pos + v < count; v++) { + gput_sum(cpu_cycles_sum, cpu_cycles, gput_line(0)); if ((list[v] & 0xf000f000) == 0x50005000) break; } len += v - 3; break; + case 0x50 ... 0x57: + gput_sum(cpu_cycles_sum, cpu_cycles, gput_line(0)); + break; case 0x58 ... 0x5F: for (v = 4; pos + v < count; v += 2) { + gput_sum(cpu_cycles_sum, cpu_cycles, gput_line(0)); if ((list[v] & 0xf000f000) == 0x50005000) break; } len += v - 4; break; + case 0x60 ... 0x63: + gput_sum(cpu_cycles_sum, cpu_cycles, + gput_sprite(LE16TOH(slist[4]) & 0x3ff, + LE16TOH(slist[5]) & 0x1ff)); + break; + case 0x64 ... 0x67: + gput_sum(cpu_cycles_sum, cpu_cycles, + gput_sprite(LE16TOH(slist[6]) & 0x3ff, + LE16TOH(slist[7]) & 0x1ff)); + break; + case 0x68 ... 0x6b: + gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(1, 1)); + break; + case 0x70 ... 0x77: + gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(8, 8)); + break; + case 0x78 ... 0x7f: + gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(16, 16)); + break; default: if ((cmd & 0xf8) == 0xe0) gpu.ex_regs[cmd & 7] = list[0]; @@ -338,24 +398,28 @@ static int scan_cmd_list(uint32_t *data, int count, int *last_cmd) cmd = -1; break; /* incomplete cmd */ } - if (0xa0 <= cmd && cmd <= 0xdf) + if (0x80 <= cmd && cmd <= 0xdf) break; /* image i/o */ pos += len; } + *cycles_sum_out += cpu_cycles_sum; + *cycles_last = cpu_cycles; *last_cmd = cmd; return pos; } -int do_cmd_list(uint32_t *list, int count, int *last_cmd) { +int do_cmd_list(uint32_t *list, int count, + int *cycles_sum, int *cycles_last, int *last_cmd) +{ int pos = 0; if (thread.running) { - pos = scan_cmd_list(list, count, last_cmd); + pos = scan_cmd_list(list, count, cycles_sum, cycles_last, last_cmd); video_thread_queue_cmd(list, pos, *last_cmd); } else { - pos = real_do_cmd_list(list, count, last_cmd); + pos = real_do_cmd_list(list, count, cycles_sum, cycles_last, last_cmd); memcpy(gpu.ex_regs, gpu.scratch_ex_regs, sizeof(gpu.ex_regs)); } return pos; @@ -378,8 +442,8 @@ void renderer_finish(void) { void renderer_sync_ecmds(uint32_t * ecmds) { if (thread.running) { - int dummy; - do_cmd_list(&ecmds[1], 6, &dummy); + int dummy = 0; + do_cmd_list(&ecmds[1], 6, &dummy, &dummy, &dummy); } else { real_renderer_sync_ecmds(ecmds); } diff --git a/pcsx_rearmed/plugins/gpulib/gpulib_thread_if.h b/pcsx_rearmed/plugins/gpulib/gpulib_thread_if.h index 8ce328e7..45fdfe01 100644 --- a/pcsx_rearmed/plugins/gpulib/gpulib_thread_if.h +++ b/pcsx_rearmed/plugins/gpulib/gpulib_thread_if.h @@ -24,7 +24,8 @@ extern "C" { #endif -int real_do_cmd_list(uint32_t *list, int count, int *last_cmd); +int real_do_cmd_list(uint32_t *list, int count, + int *cycles_sum_out, int *cycles_last, int *last_cmd); int real_renderer_init(void); void real_renderer_finish(void); void real_renderer_sync_ecmds(uint32_t * ecmds); diff --git a/pcsx_rearmed/plugins/gpulib/test.c b/pcsx_rearmed/plugins/gpulib/test.c index 80d0e9ef..3f24cc4f 100644 --- a/pcsx_rearmed/plugins/gpulib/test.c +++ b/pcsx_rearmed/plugins/gpulib/test.c @@ -88,13 +88,13 @@ int main(int argc, char *argv[]) pcnt_init(); renderer_init(); - memcpy(gpu.vram, state.vram, sizeof(gpu.vram)); + memcpy(gpu.vram, state.vram, 1024*512*2); if ((state.gpu_register[8] & 0x24) == 0x24) renderer_set_interlace(1, !(state.status >> 31)); start_cycles = pcnt_get(); - do_cmd_list(list, size / 4, &dummy); + do_cmd_list(list, size / 4, &dummy, &dummy); renderer_flush_queues(); printf("%u\n", pcnt_get() - start_cycles); diff --git a/pcsx_rearmed/plugins/gpulib/vout_pl.c b/pcsx_rearmed/plugins/gpulib/vout_pl.c index f5e60f92..5c727bbc 100644 --- a/pcsx_rearmed/plugins/gpulib/vout_pl.c +++ b/pcsx_rearmed/plugins/gpulib/vout_pl.c @@ -29,7 +29,7 @@ static void check_mode_change(int force) { int w = gpu.screen.hres; int h = gpu.screen.vres; - int w_out, h_out; + int w_out, h_out, bpp = 16; if (gpu.state.screen_centering_type == C_BORDERLESS) h = gpu.screen.h; @@ -45,6 +45,11 @@ static void check_mode_change(int force) w_out *= 2; h_out *= 2; } + if (gpu.status & PSX_GPU_STATUS_RGB24) { + // some asm relies on this alignment + w_out = (w_out + 7) & ~7; + bpp = 24; + } gpu.state.downscale_active = gpu.get_downscale_buffer != NULL && gpu.state.downscale_enable @@ -64,8 +69,7 @@ static void check_mode_change(int force) gpu.state.h_out_old = h_out; if (w_out != 0 && h_out != 0) - cbs->pl_vout_set_mode(w_out, h_out, w, h, - (gpu.status & PSX_GPU_STATUS_RGB24) ? 24 : 16); + cbs->pl_vout_set_mode(w_out, h_out, w, h, bpp); } } diff --git a/pcsx_rearmed/plugins/spunull/spunull.c b/pcsx_rearmed/plugins/spunull/spunull.c index ece5db93..7f16ed5e 100644 --- a/pcsx_rearmed/plugins/spunull/spunull.c +++ b/pcsx_rearmed/plugins/spunull/spunull.c @@ -284,6 +284,11 @@ void CALLBACK SPUplayADPCMchannel(xa_decode_t *xap) { } +void CALLBACK SPUsetCDvol(unsigned char ll, unsigned char lr, + unsigned char rl, unsigned char rr, unsigned int cycle) +{ +} + //////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////