mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-27 02:32:02 -04:00
Expand Einhander player bounds for native widescreen
This commit is contained in:
committed by
Matthew Stanley
parent
153db9e4d1
commit
28165d6421
@@ -0,0 +1,10 @@
|
||||
# Typed widescreen signed bounds
|
||||
|
||||
Source: [PSXRecomp PR #15](https://github.com/mstan/psxrecomp/pull/15),
|
||||
commit [`f44f365eb91a30396f05f0f52529d4b01b026099`](https://github.com/douglasjv/psxrecomp-tweaks/commit/f44f365eb91a30396f05f0f52529d4b01b026099).
|
||||
|
||||
This branch isolates the opt-in guarded LUI transform across static generation,
|
||||
captured overlays, SLJIT, and the dirty interpreter. The source behavior is
|
||||
parked for testing with two known review questions: runtime registration clamps
|
||||
at 64 sites and scaling currently includes the renderer cull margin. Textured
|
||||
edges, debug tooling, and title-specific addresses are excluded.
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "function_analysis.h"
|
||||
#include "control_flow.h"
|
||||
#include "../src/annotations.hpp"
|
||||
#include "../src/config_loader.h"
|
||||
|
||||
namespace PSXRecomp {
|
||||
|
||||
@@ -43,6 +44,7 @@ struct CodeGenConfig {
|
||||
// mismatch is EXPECTED (apply the transform only where the bytes match, skip
|
||||
// it elsewhere) rather than a hard config error.
|
||||
bool overlay_mode = false;
|
||||
std::vector<PSXRecompV4::WidescreenSignedBoundSite> ws_signed_x_bound_sites;
|
||||
std::string indent; // Indentation string (default: " ")
|
||||
// Widescreen sprite-tag hooks ([widescreen] sprite_tag_funcs): functions
|
||||
// that get a psx_ws_sprite_tag(cpu) callback emitted at entry, so the
|
||||
|
||||
@@ -758,6 +758,21 @@ std::string CodeGenerator::translate_instruction(uint32_t addr, uint32_t instr)
|
||||
|
||||
std::string code;
|
||||
|
||||
for (const auto& site : config_.ws_signed_x_bound_sites) {
|
||||
if ((site.address & 0x1FFFFFFFu) != (addr & 0x1FFFFFFFu)) continue;
|
||||
if (instr != site.expected) {
|
||||
if (config_.overlay_mode) continue;
|
||||
fmt::print(stderr,
|
||||
"ERROR: signed_x_bound expected 0x{:08X} at 0x{:08X}, found 0x{:08X}\n",
|
||||
site.expected, addr, instr);
|
||||
std::exit(1);
|
||||
}
|
||||
const int32_t vanilla = (int32_t)((instr & 0xFFFFu) << 16);
|
||||
return fmt::format("{} = (uint32_t)psx_ws_player_x_bound((int32_t)0x{:08X});"
|
||||
" /* typed native-wide signed X bound */{}",
|
||||
reg_name(get_rt(instr)), (uint32_t)vanilla, comment);
|
||||
}
|
||||
|
||||
// Widescreen automatic far-backdrop column PRELOAD ([widescreen.cull]
|
||||
// auto_backdrop). At a detected window's START/END finalize, route the value
|
||||
// through psx_ws_backdrop_value(orig, is_end): identity at 4:3, but in
|
||||
@@ -2635,6 +2650,7 @@ std::string CodeGenerator::generate_file(
|
||||
ss << "extern void psx_ws_sprite_tag(CPUState* cpu); /* widescreen prim tag (gpu.c) */\n";
|
||||
ss << "extern void psx_ws_mmx6_bg_stage_init(void); /* ws 2D stage reveal invalidation (gpu.c) */\n";
|
||||
ss << "extern int psx_ws_x_margin(void); /* widescreen cull-margin term (gpu.c) */\n";
|
||||
ss << "extern int32_t psx_ws_player_x_bound(int32_t vanilla); /* typed gameplay X bound */\n";
|
||||
ss << "extern int psx_ws_cull_sltiu(uint32_t sx, uint32_t imm); /* ws auto screen-x cull (gpu.c) */\n";
|
||||
ss << "extern int psx_ws_cull_slti(uint32_t sx, uint32_t imm); /* ws cull signed right edge (gpu.c) */\n";
|
||||
ss << "extern int psx_ws_cull_bltz(uint32_t v); /* ws cull signed left edge (gpu.c) */\n";
|
||||
|
||||
@@ -783,6 +783,7 @@ GameConfig load_game_config(const fs::path& config_path_in) {
|
||||
bool ws_nw_textured_edges = false;
|
||||
int ws_nw_textured_edge_scale = 0;
|
||||
bool ws_nw_full_mirror = false;
|
||||
std::vector<WidescreenSignedBoundSite> ws_signed_x_bound_sites;
|
||||
bool ws_offered = true;
|
||||
bool ws_ultrawide_offered = false;
|
||||
if (cfg.contains("widescreen")) {
|
||||
@@ -851,6 +852,25 @@ GameConfig load_game_config(const fs::path& config_path_in) {
|
||||
}
|
||||
if (ws.contains("nw_full_mirror"))
|
||||
ws_nw_full_mirror = toml::find<bool>(ws, "nw_full_mirror");
|
||||
if (ws.contains("signed_x_bound")) {
|
||||
std::set<uint32_t> seen;
|
||||
for (const auto& item : toml::find<toml::array>(ws, "signed_x_bound")) {
|
||||
WidescreenSignedBoundSite site;
|
||||
site.address = parse_hex(toml::find<std::string>(item, "address"),
|
||||
"widescreen.signed_x_bound.address");
|
||||
site.expected = parse_hex(toml::find<std::string>(item, "expected"),
|
||||
"widescreen.signed_x_bound.expected");
|
||||
if ((site.expected >> 26) != 0x0Fu)
|
||||
throw std::runtime_error(fmt::format(
|
||||
"{}: [[widescreen.signed_x_bound]] expected must be LUI",
|
||||
config_path.string()));
|
||||
if (!seen.insert(site.address & 0x1FFFFFFFu).second)
|
||||
throw std::runtime_error(fmt::format(
|
||||
"{}: duplicate [[widescreen.signed_x_bound]] address 0x{:08X}",
|
||||
config_path.string(), site.address));
|
||||
ws_signed_x_bound_sites.push_back(site);
|
||||
}
|
||||
}
|
||||
if (ws.contains("offer"))
|
||||
ws_offered = toml::find<bool>(ws, "offer");
|
||||
if (ws.contains("offer_ultrawide"))
|
||||
@@ -1044,6 +1064,7 @@ GameConfig load_game_config(const fs::path& config_path_in) {
|
||||
/*ws_nw_textured_edges*/ ws_nw_textured_edges,
|
||||
/*ws_nw_textured_edge_scale*/ ws_nw_textured_edge_scale,
|
||||
/*ws_nw_full_mirror*/ ws_nw_full_mirror,
|
||||
/*ws_signed_x_bound_sites*/ ws_signed_x_bound_sites,
|
||||
/*ws_offered*/ ws_offered,
|
||||
/*ws_ultrawide_offered*/ ws_ultrawide_offered,
|
||||
/*ws_bg2d_count_site*/ ws_bg2d_count_site,
|
||||
|
||||
@@ -39,6 +39,10 @@ namespace PSXRecompV4 {
|
||||
// digital — always present a digital pad (id 0x41); sticks disabled.
|
||||
enum PadMode { PAD_MODE_HYBRID = 0, PAD_MODE_ANALOG = 1, PAD_MODE_DIGITAL = 2 };
|
||||
|
||||
struct WidescreenSignedBoundSite {
|
||||
uint32_t address = 0;
|
||||
uint32_t expected = 0; // guarded LUI instruction
|
||||
};
|
||||
// Parse/format a pad mode. pad_mode_from_string accepts "hybrid"/"analog"/
|
||||
// "digital" (case-insensitive) and returns `fallback` for anything else.
|
||||
int pad_mode_from_string(const std::string& s, int fallback);
|
||||
@@ -570,6 +574,10 @@ struct GameConfig {
|
||||
// transformed in the mirror.
|
||||
bool ws_nw_full_mirror = false;
|
||||
|
||||
// [[widescreen.signed_x_bound]] guarded LUI sites whose signed Q16
|
||||
// constants scale with the active native-wide field and remain identity in
|
||||
// 4:3/menus/FMV. Shared by static codegen, overlay JIT, and interpreter.
|
||||
std::vector<WidescreenSignedBoundSite> ws_signed_x_bound_sites;
|
||||
// [widescreen] offer — whether the launcher OFFERS its EXPERIMENTAL
|
||||
// Widescreen toggle for this title. Default true. Set false while a
|
||||
// title's widescreen is unported/unvalidated (e.g. MMX4 at bring-up):
|
||||
|
||||
@@ -131,6 +131,7 @@ int main(int argc, char** argv) {
|
||||
bool ws_auto_screen_x_cull = false; // [widescreen.cull] auto_screen_x
|
||||
std::set<uint32_t> persist_init_sites; // [persist_options] init-store hooks (game_options.toml)
|
||||
std::vector<PSXRecompV4::RecompilerPatch> instruction_patches;
|
||||
std::vector<PSXRecompV4::WidescreenSignedBoundSite> ws_signed_x_bound_sites;
|
||||
bool ws_auto_backdrop_preload = false; // [widescreen.cull] auto_backdrop
|
||||
uint32_t ws_bg2d_count_site = 0, ws_bg2d_startcol_site = 0,
|
||||
ws_bg2d_startx_site = 0,
|
||||
@@ -172,6 +173,7 @@ int main(int argc, char** argv) {
|
||||
if (cfg.ws_bg2d_bufbase_site) ws_bg2d_bufbase_site = cfg.ws_bg2d_bufbase_site;
|
||||
if (cfg.ws_bg2d_cap_site) ws_bg2d_cap_site = cfg.ws_bg2d_cap_site;
|
||||
if (cfg.ws_bg2d_init_func) ws_bg2d_init_func = cfg.ws_bg2d_init_func;
|
||||
ws_signed_x_bound_sites = cfg.ws_signed_x_bound_sites;
|
||||
// [persist_options] init-store hook sites live in a dedicated
|
||||
// game_options.toml next to game.toml (the game's own native OPTION
|
||||
// settings, kept separate from game.toml/settings.toml). Best-effort:
|
||||
@@ -245,6 +247,9 @@ int main(int argc, char** argv) {
|
||||
ws_auto_backdrop_preload = ws_auto_backdrop_preload || wscfg.ws_auto_backdrop_preload;
|
||||
PSXRecompV4::merge_recompiler_patches(
|
||||
instruction_patches, wscfg.recompiler_patches);
|
||||
ws_signed_x_bound_sites.insert(ws_signed_x_bound_sites.end(),
|
||||
wscfg.ws_signed_x_bound_sites.begin(),
|
||||
wscfg.ws_signed_x_bound_sites.end());
|
||||
if (wscfg.ws_bg2d_init_func) ws_bg2d_init_func = wscfg.ws_bg2d_init_func;
|
||||
fmt::print("ws-config: {} (backdrop_x sites={}, unsquash funcs={})\n",
|
||||
ws_config_path.string(), ws_backdrop_x.size(), ws_backdrop_unsquash.size());
|
||||
@@ -811,6 +816,7 @@ int main(int argc, char** argv) {
|
||||
codegen_config.emit_line_numbers = true;
|
||||
codegen_config.split_mid_function_targets = !overlay_mode;
|
||||
codegen_config.overlay_mode = overlay_mode;
|
||||
codegen_config.ws_signed_x_bound_sites = ws_signed_x_bound_sites;
|
||||
codegen_config.ws_sprite_tag_funcs = ws_tag_funcs;
|
||||
codegen_config.ws_bg2d_init_func = ws_bg2d_init_func;
|
||||
codegen_config.ws_cull_bias_sites = ws_cull_bias;
|
||||
|
||||
@@ -33,6 +33,7 @@ enum {
|
||||
SLJIT_HLP_CALL, /* psx_sljit_call — jal/jalr call contract */
|
||||
SLJIT_HLP_WS_CULL_SLTI, /* psx_ws_cull_slti — signed funnel right edge (appended) */
|
||||
SLJIT_HLP_WS_CULL_BLTZ, /* psx_ws_cull_bltz — signed funnel left edge (appended) */
|
||||
SLJIT_HLP_WS_PLAYER_X_BOUND, /* typed native-wide signed gameplay bound */
|
||||
SLJIT_HLP_COUNT
|
||||
};
|
||||
|
||||
|
||||
@@ -145,6 +145,12 @@ void gpu_ws_set_explicit_cull_sites(const uint32_t *bias, int nbias,
|
||||
const uint32_t *slti, int nslti);
|
||||
int psx_ws_is_cull_bias_site(uint32_t pc);
|
||||
int psx_ws_is_cull_slti_site(uint32_t pc);
|
||||
/* Scale a signed Q16 horizontal gameplay limit into the active native-wide
|
||||
* game field. Identity at 4:3 / menus / FMV. */
|
||||
int32_t psx_ws_player_x_bound(int32_t vanilla);
|
||||
void gpu_ws_set_signed_x_bound_sites(const uint32_t *addresses,
|
||||
const uint32_t *expected, int count);
|
||||
int psx_ws_is_signed_x_bound_site(uint32_t pc, uint32_t instr);
|
||||
|
||||
/* Shared render-funnel screen-X cull widening ([widescreen.cull] auto_screen_x):
|
||||
* the gcc emit, the sljit JIT, and the interpreter all route a flagged
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
* 4: continuation-passing (PSX_CPS, RECURSION_BUG.md §25) — overlay funcs
|
||||
* tail-transfer + carry an entry-switch; the loader routes continuations.
|
||||
* Fresh namespace so CPS DLLs never reuse a legacy (unit-model) cg3 DLL. */
|
||||
#define PSX_OVERLAY_CODEGEN_VER 4
|
||||
#define PSX_OVERLAY_CODEGEN_VER 5
|
||||
|
||||
/* Auto codegen hash (generated by hash_codegen.cmake from the recompiler codegen
|
||||
* sources). Folded into the cache PATH next to cg<N> (gcc/<arch-abi>/cg<N>_<hash>/)
|
||||
|
||||
@@ -1575,7 +1575,10 @@ static int exec_one(CPUState *cpu, uint32_t pc, uint32_t *next_pc_out) {
|
||||
cpu->gpr[0] = 0;
|
||||
return 0;
|
||||
case 0x0F: /* LUI rt, imm */
|
||||
cpu->gpr[rt] = imm << 16;
|
||||
if (psx_ws_is_signed_x_bound_site(pc, insn))
|
||||
cpu->gpr[rt] = (uint32_t)psx_ws_player_x_bound((int32_t)(imm << 16));
|
||||
else
|
||||
cpu->gpr[rt] = imm << 16;
|
||||
cpu->gpr[0] = 0;
|
||||
return 0;
|
||||
case 0x10: { /* COP0 */
|
||||
|
||||
@@ -347,6 +347,35 @@ int psx_ws_x_margin(void) {
|
||||
return (160 * (ws_xden - ws_xnum) + ws_xnum / 2) / ws_xnum;
|
||||
}
|
||||
|
||||
int32_t psx_ws_player_x_bound(int32_t vanilla)
|
||||
{
|
||||
const int margin = psx_ws_x_margin();
|
||||
if (margin <= 0) return vanilla;
|
||||
return (int32_t)(((int64_t)vanilla * (320 + 2 * margin)) / 320);
|
||||
}
|
||||
|
||||
#define WS_SIGNED_BOUND_MAX 64
|
||||
static uint32_t ws_signed_bound_addr[WS_SIGNED_BOUND_MAX];
|
||||
static uint32_t ws_signed_bound_expected[WS_SIGNED_BOUND_MAX];
|
||||
static int ws_signed_bound_count = 0;
|
||||
void gpu_ws_set_signed_x_bound_sites(const uint32_t *addresses,
|
||||
const uint32_t *expected, int count) {
|
||||
if (count < 0) count = 0;
|
||||
if (count > WS_SIGNED_BOUND_MAX) count = WS_SIGNED_BOUND_MAX;
|
||||
ws_signed_bound_count = count;
|
||||
for (int i = 0; i < count; i++) {
|
||||
ws_signed_bound_addr[i] = addresses[i] & 0x1FFFFFFFu;
|
||||
ws_signed_bound_expected[i] = expected[i];
|
||||
}
|
||||
}
|
||||
int psx_ws_is_signed_x_bound_site(uint32_t pc, uint32_t instr) {
|
||||
const uint32_t phys = pc & 0x1FFFFFFFu;
|
||||
for (int i = 0; i < ws_signed_bound_count; i++)
|
||||
if (ws_signed_bound_addr[i] == phys && ws_signed_bound_expected[i] == instr)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ---- Capcom 2D background tile-loop widen ([widescreen.bg2d]) --------------
|
||||
* Mega Man X5/X6 use a pure-2D sprite engine that renders only a 4:3 (320px) field
|
||||
* of view — there is no overscan to "reveal." Its per-layer background renderer
|
||||
|
||||
@@ -347,6 +347,7 @@ static bool g_ws_hud_sprt = false;
|
||||
* units include that ABI header and do not need this frontend-only setter. */
|
||||
extern "C" void gpu_ws_set_clear_reveal(int on);
|
||||
extern "C" void gpu_ws_set_nw_textured_edges(int on, int scale_pct);
|
||||
extern "C" void gpu_ws_set_signed_x_bound_sites(const uint32_t*, const uint32_t*, int);
|
||||
/* Widescreen engages at game entry (fntrace_is_game_started): the BIOS boot
|
||||
* — Sony logo, PS logo, shell — presents authentic 4:3 with no GTE squash.
|
||||
* Starts true when the configured aspect is already 4:3 (nothing to engage). */
|
||||
@@ -2848,6 +2849,17 @@ int main(int argc, char** argv) {
|
||||
gpu_ws_set_nw_textured_edges(gc.ws_nw_textured_edges ? 1 : 0,
|
||||
gc.ws_nw_textured_edge_scale);
|
||||
gl_renderer_set_wide_fast(gc.ws_nw_full_mirror ? 0 : 1);
|
||||
{
|
||||
std::vector<uint32_t> addresses, expected;
|
||||
addresses.reserve(gc.ws_signed_x_bound_sites.size());
|
||||
expected.reserve(gc.ws_signed_x_bound_sites.size());
|
||||
for (const auto& site : gc.ws_signed_x_bound_sites) {
|
||||
addresses.push_back(site.address);
|
||||
expected.push_back(site.expected);
|
||||
}
|
||||
gpu_ws_set_signed_x_bound_sites(addresses.data(), expected.data(),
|
||||
(int)addresses.size());
|
||||
}
|
||||
/* [widescreen] clear_reveal — enable opted-in scene/map-boundary
|
||||
* cleanup of synthetic native-wide margins. */
|
||||
gpu_ws_set_clear_reveal(gc.ws_clear_reveal ? 1 : 0);
|
||||
|
||||
@@ -163,6 +163,7 @@ static uint32_t s_gpr_lru;
|
||||
static int s_frag_ws_cull;
|
||||
extern int psx_ws_cull_sltiu(uint32_t sx, uint32_t imm); /* gpu.c — shared widen */
|
||||
extern int psx_ws_cull_slti(uint32_t sx, uint32_t imm); /* gpu.c — signed right edge */
|
||||
extern int32_t psx_ws_player_x_bound(int32_t vanilla); /* gpu.c — gameplay X clamp */
|
||||
extern int psx_ws_cull_bltz(uint32_t v); /* gpu.c — signed left edge */
|
||||
extern int psx_ws_is_cull_w_imm(uint32_t imm); /* gpu.c — per-game W-imm set */
|
||||
extern int psx_ws_auto_cull_on(void); /* gpu.c — per-game opt-in gate */
|
||||
@@ -371,6 +372,17 @@ void overlay_sljit_init_helpers(CPUState *cpu) {
|
||||
cpu->sljit_helpers[SLJIT_HLP_CALL] = (void *)psx_sljit_call;
|
||||
cpu->sljit_helpers[SLJIT_HLP_WS_CULL_SLTI] = (void *)psx_ws_cull_slti;
|
||||
cpu->sljit_helpers[SLJIT_HLP_WS_CULL_BLTZ] = (void *)psx_ws_cull_bltz;
|
||||
cpu->sljit_helpers[SLJIT_HLP_WS_PLAYER_X_BOUND] = (void *)psx_ws_player_x_bound;
|
||||
}
|
||||
|
||||
static void emit_ws_player_x_bound(struct sljit_compiler *C, uint32_t rt, int32_t vanilla) {
|
||||
sljit_emit_op1(C, SLJIT_MOV32, SLJIT_R0, 0, SLJIT_IMM, (sljit_sw)vanilla);
|
||||
sljit_emit_op1(C, SLJIT_MOV, SLJIT_R2, 0, SLJIT_MEM1(R_CPU),
|
||||
(sljit_sw)(offsetof(CPUState, sljit_helpers)
|
||||
+ (size_t)SLJIT_HLP_WS_PLAYER_X_BOUND * sizeof(void *)));
|
||||
sljit_emit_icall(C, SLJIT_CALL, SLJIT_ARGS1(32, 32), SLJIT_R2, 0);
|
||||
sljit_emit_op1(C, SLJIT_MOV32, gpr_dst(C, rt), 0, SLJIT_R0, 0);
|
||||
gpr_unpin();
|
||||
}
|
||||
|
||||
/* Emit `rt = <cull helper>(gpr[rs], imm)` for a flagged auto_screen_x cull
|
||||
@@ -401,7 +413,7 @@ enum { EMIT_OK = 0, EMIT_TERM = 1, EMIT_ABORT = 2 };
|
||||
* is `jr $ra` (the only terminator this slice supports — caller then emits the
|
||||
* delay slot + the shard return), or EMIT_ABORT for anything outside the slice
|
||||
* (any other control transfer, or an unsupported opcode). */
|
||||
static int emit_one(struct sljit_compiler *C, uint32_t insn, int bd_kind, int bd_cols) {
|
||||
static int emit_one(struct sljit_compiler *C, uint32_t pc, uint32_t insn, int bd_kind, int bd_cols) {
|
||||
uint32_t op = f_op(insn), rs = f_rs(insn), rt = f_rt(insn);
|
||||
uint32_t rd = f_rd(insn), sh = f_sh(insn), fn = f_fn(insn);
|
||||
uint32_t imm = f_imm(insn);
|
||||
@@ -615,7 +627,10 @@ static int emit_one(struct sljit_compiler *C, uint32_t insn, int bd_kind, int bd
|
||||
return EMIT_OK;
|
||||
}
|
||||
case 0x0F: /* LUI rt = imm << 16 */
|
||||
sljit_emit_op1(C, SLJIT_MOV32, gpr_dst(C, rt), 0, SLJIT_IMM, (sljit_sw)(imm << 16));
|
||||
if (psx_ws_is_signed_x_bound_site(pc, insn))
|
||||
emit_ws_player_x_bound(C, rt, (int32_t)(imm << 16));
|
||||
else
|
||||
sljit_emit_op1(C, SLJIT_MOV32, gpr_dst(C, rt), 0, SLJIT_IMM, (sljit_sw)(imm << 16));
|
||||
return EMIT_OK;
|
||||
case 0x20: emit_load(C, offsetof(CPUState, read_byte), SLJIT_MOV_S8, rt, rs, simm); return EMIT_OK; /* LB */
|
||||
case 0x21: emit_load(C, offsetof(CPUState, read_half), SLJIT_MOV_S16, rt, rs, simm); return EMIT_OK; /* LH */
|
||||
@@ -996,7 +1011,7 @@ void overlay_sljit_try_compile(uint32_t entry,
|
||||
pending = PEND_CALL;
|
||||
continue;
|
||||
}
|
||||
if (emit_one(C, insn, s_bd_kind[i], s_bd_cols[i]) != EMIT_OK) { aborted = 1; break; }
|
||||
if (emit_one(C, entry + i * 4u, insn, s_bd_kind[i], s_bd_cols[i]) != EMIT_OK) { aborted = 1; break; }
|
||||
} else {
|
||||
/* This instruction is the delay slot of the pending control insn;
|
||||
* it must be a plain, supported, non-control op (the constraint the
|
||||
@@ -1006,7 +1021,7 @@ void overlay_sljit_try_compile(uint32_t entry,
|
||||
* the pending transfer. */
|
||||
int32_t dummy = 0;
|
||||
if (classify_control(insn, i * 4u, entry_phys, &dummy) != CTRL_NONE) { aborted = 1; break; }
|
||||
if (emit_one(C, insn, s_bd_kind[i], s_bd_cols[i]) != EMIT_OK) { aborted = 1; break; }
|
||||
if (emit_one(C, entry + i * 4u, insn, s_bd_kind[i], s_bd_cols[i]) != EMIT_OK) { aborted = 1; break; }
|
||||
gpr_flush(C);
|
||||
if (pending == PEND_RET) {
|
||||
if (g_psx_cps_mode) {
|
||||
|
||||
Reference in New Issue
Block a user