mirror of https://github.com/snesrev/smw.git
Add support for two gamepads
This commit is contained in:
parent
c96e0c98d7
commit
f514ab59d0
10
smw.ini
10
smw.ini
|
|
@ -66,6 +66,9 @@ Controls = Up, Down, Left, Right, Right Shift, Return, x, z, s, a, c, v
|
|||
# This one is suitable for AZERTY keyboards.
|
||||
#Controls = Up, Down, Left, Right, Right Shift, Return, x, w, s, q, c, v
|
||||
|
||||
# For player 2
|
||||
#ControlsP2 = Shift+Up, Shift+Down, Shift+Left, Shift+Right, Shift+Right Shift, Shift+Return, Shift+x, Shift+z, Shift+s, Shift+a, Shift+c, Shift+v
|
||||
|
||||
CheatLife = w
|
||||
CheatJump = Ctrl+q
|
||||
ClearKeyLog = k
|
||||
|
|
@ -90,7 +93,14 @@ LoadRef = 1,2,3,4,5,6,7,8,9,0,-,=,Backspace
|
|||
ReplayRef = Ctrl+1,Ctrl+2,Ctrl+3,Ctrl+4,Ctrl+5,Ctrl+6,Ctrl+7,Ctrl+8,Ctrl+9,Ctrl+0,Ctrl+-,Ctrl+=,Ctrl+Backspace
|
||||
|
||||
[GamepadMap]
|
||||
# Whether the gamepads will be enabled. The game will not use them unless they're on.
|
||||
EnableGamepad1 = true
|
||||
EnableGamepad2 = true
|
||||
|
||||
# Any keys used in KeyMap can be used also in this section.
|
||||
|
||||
# The shoulder button is called L1/Lb and L2, and the thumbstick button is called L3
|
||||
Controls = DpadUp, DpadDown, DpadLeft, DpadRight, Back, Start, B, A, Y, X, Lb, Rb
|
||||
|
||||
# For player 2.
|
||||
ControlsP2 = DpadUp, DpadDown, DpadLeft, DpadRight, Back, Start, B, A, Y, X, Lb, Rb
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@ static uint8 kPatchedCarrysOrg[1024];
|
|||
static void VerifySnapshotsEq(Snapshot *b, Snapshot *a, Snapshot *prev);
|
||||
static void MakeSnapshot(Snapshot *s);
|
||||
static void RestoreSnapshot(Snapshot *s);
|
||||
static void RtlRunFrameCompare(uint16 input, int run_what);
|
||||
|
||||
uint8_t *SnesRomPtr(uint32 v) {
|
||||
return (uint8 *)RomPtr(v);
|
||||
|
|
@ -252,8 +251,6 @@ Snes *SnesInit(const uint8 *data, int data_size) {
|
|||
g_dma = g_snes->dma;
|
||||
g_use_my_apu_code = (g_runmode != RM_THEIRS);
|
||||
|
||||
RtlSetupEmuCallbacks(NULL, &RtlRunFrameCompare, NULL);
|
||||
|
||||
if (data_size != 0 && g_runmode != RM_MINE) {
|
||||
bool loaded = snes_loadRom(g_snes, data, data_size);
|
||||
if (!loaded) {
|
||||
|
|
@ -362,9 +359,7 @@ getout:
|
|||
g_got_mismatch_count--;
|
||||
}
|
||||
|
||||
static void RtlRunFrameCompare(uint16 input, int run_what) {
|
||||
g_snes->input1->currentState = input;
|
||||
|
||||
void RtlRunFrameCompare() {
|
||||
g_use_my_apu_code = (g_runmode != RM_THEIRS);
|
||||
|
||||
if (g_runmode == RM_THEIRS) {
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ typedef void CpuInfraInitializeFunc(void);
|
|||
typedef void RunOneFrameOfGameFunc(void);
|
||||
typedef void FixSnapshotForCompareFunc(Snapshot *b, Snapshot *a);
|
||||
|
||||
void RtlRunFrameCompare(void);
|
||||
|
||||
typedef struct RtlGameInfo {
|
||||
const char *title;
|
||||
uint8 game_id;
|
||||
|
|
|
|||
115
src/common_rtl.c
115
src/common_rtl.c
|
|
@ -26,30 +26,6 @@ Ppu *g_ppu, *g_my_ppu;
|
|||
Dma *g_dma;
|
||||
bool g_custom_music;
|
||||
|
||||
static uint8 *g_rtl_memory_ptr;
|
||||
static RunFrameFunc *g_rtl_runframe;
|
||||
static SyncAllFunc *g_rtl_syncall;
|
||||
|
||||
void RtlSetupEmuCallbacks(uint8 *emu_ram, RunFrameFunc *func, SyncAllFunc *sync_all) {
|
||||
g_rtl_memory_ptr = emu_ram;
|
||||
g_rtl_runframe = func;
|
||||
g_rtl_syncall = sync_all;
|
||||
}
|
||||
|
||||
static void RtlSynchronizeWholeState(void) {
|
||||
if (g_rtl_syncall)
|
||||
g_rtl_syncall();
|
||||
}
|
||||
|
||||
// |ptr| must be a pointer into g_ram, will synchronize the RAM memory with the
|
||||
// emulator.
|
||||
static void RtlSyncMemoryRegion(void *ptr, size_t n) {
|
||||
uint8 *data = (uint8 *)ptr;
|
||||
assert(data >= g_ram && data < g_ram + 0x20000);
|
||||
if (g_rtl_memory_ptr)
|
||||
memcpy(g_rtl_memory_ptr + (data - g_ram), data, n);
|
||||
}
|
||||
|
||||
void ByteArray_AppendVl(ByteArray *arr, uint32 v) {
|
||||
for (; v >= 255; v -= 255)
|
||||
ByteArray_AppendByte(arr, 255);
|
||||
|
|
@ -81,7 +57,6 @@ void loadFunc(SaveLoadInfo *sli, void *data, size_t data_size) {
|
|||
static void LoadSnesState(SaveLoadInfo *sli) {
|
||||
// Do the actual loading
|
||||
snes_saveload(g_snes, sli);
|
||||
RtlSynchronizeWholeState();
|
||||
}
|
||||
|
||||
static void SaveSnesState(SaveLoadInfo *sli) {
|
||||
|
|
@ -89,7 +64,7 @@ static void SaveSnesState(SaveLoadInfo *sli) {
|
|||
}
|
||||
|
||||
typedef struct StateRecorder {
|
||||
uint16 last_inputs;
|
||||
uint32 last_inputs;
|
||||
uint32 frames_since_last;
|
||||
uint32 total_frames;
|
||||
|
||||
|
|
@ -100,6 +75,7 @@ typedef struct StateRecorder {
|
|||
uint32 snapshot_flags;
|
||||
uint8 replay_cmd;
|
||||
bool replay_mode;
|
||||
uint8 cur_player;
|
||||
|
||||
ByteArray log;
|
||||
ByteArray base_snapshot;
|
||||
|
|
@ -122,25 +98,31 @@ void StateRecorder_RecordCmd(StateRecorder *sr, uint8 cmd) {
|
|||
ByteArray_AppendVl(&sr->log, frames - x);
|
||||
}
|
||||
|
||||
void StateRecorder_Record(StateRecorder *sr, uint16 inputs) {
|
||||
uint16 diff = inputs ^ sr->last_inputs;
|
||||
if (diff != 0) {
|
||||
sr->last_inputs = inputs;
|
||||
// printf("0x%.4x %d: ", diff, sr->frames_since_last);
|
||||
// size_t lb = sr->log.size;
|
||||
for (int i = 0; i < 12; i++) {
|
||||
if ((diff >> i) & 1)
|
||||
static void StateRecorder_RecordKeyDiff(StateRecorder *sr, uint32 diff) {
|
||||
for (int i = 0; diff; i++, diff >>= 1) {
|
||||
if (diff & 1) {
|
||||
int player = (i >= 12);
|
||||
i -= player * 12;
|
||||
if (player != sr->cur_player) {
|
||||
sr->cur_player = player;
|
||||
ByteArray_AppendByte(&sr->log, 0xfc + player);
|
||||
}
|
||||
StateRecorder_RecordCmd(sr, i << 4);
|
||||
}
|
||||
// while (lb < sr->log.size)
|
||||
// printf("%.2x ", sr->log.data[lb++]);
|
||||
// printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
void StateRecorder_Record(StateRecorder *sr, uint32 inputs) {
|
||||
uint32 diff = (inputs ^ sr->last_inputs) & 0xffffff;
|
||||
sr->last_inputs = inputs;
|
||||
if (diff)
|
||||
StateRecorder_RecordKeyDiff(sr, diff);
|
||||
sr->frames_since_last++;
|
||||
sr->total_frames++;
|
||||
}
|
||||
|
||||
void StateRecorder_RecordPatchByte(StateRecorder *sr, uint32 addr, const uint8 *value, int num) {
|
||||
void StateRecorder_RecordPatchByte(StateRecorder *sr, const uint8 *value, int num) {
|
||||
uint32 addr = value - g_ram;
|
||||
assert(addr < 0x20000);
|
||||
|
||||
// printf("%d: PatchByte(0x%x, 0x%x. %d): ", sr->frames_since_last, addr, *value, num);
|
||||
|
|
@ -174,8 +156,6 @@ void RtlReset(int mode) {
|
|||
RtlRestoreMusicAfterLoad_Locked(true);
|
||||
RtlApuUnlock();
|
||||
|
||||
RtlSynchronizeWholeState();
|
||||
|
||||
if ((mode & 2) == 0)
|
||||
StateRecorder_Init(&state_recorder);
|
||||
}
|
||||
|
|
@ -216,6 +196,7 @@ void StateRecorder_Load(StateRecorder *sr, FILE *f, bool replay_mode) {
|
|||
sr->snapshot_flags = hdr[9];
|
||||
sr->replay_next_cmd_at = 0;
|
||||
sr->replay_mode = replay_mode;
|
||||
sr->cur_player = 0;
|
||||
if (replay_mode) {
|
||||
sr->frames_since_last = 0;
|
||||
sr->last_inputs = 0;
|
||||
|
|
@ -269,6 +250,12 @@ void StateRecorder_Save(StateRecorder *sr, FILE *f, bool saving_with_bug) {
|
|||
assert(sr->base_snapshot.size == 0 ||
|
||||
sr->base_snapshot.size == savest.array.size || sr->base_snapshot.size == g_sram_size);
|
||||
|
||||
// Before saving, reset the cur player
|
||||
if (sr->cur_player) {
|
||||
sr->cur_player = 0;
|
||||
ByteArray_AppendVl(&sr->log, 0xfc);
|
||||
}
|
||||
|
||||
hdr[0] = 2;
|
||||
hdr[1] = sr->total_frames;
|
||||
hdr[2] = (uint32)sr->log.size;
|
||||
|
|
@ -305,12 +292,9 @@ void StateRecorder_ClearKeyLog(StateRecorder *sr) {
|
|||
memset(&sr->log, 0, sizeof(sr->log));
|
||||
// If there are currently any active inputs, record them initially at timestamp 0.
|
||||
sr->frames_since_last = 0;
|
||||
if (sr->last_inputs) {
|
||||
for (int i = 0; i < 12; i++) {
|
||||
if ((sr->last_inputs >> i) & 1)
|
||||
StateRecorder_RecordCmd(sr, i << 4);
|
||||
}
|
||||
}
|
||||
sr->cur_player = 0;
|
||||
StateRecorder_RecordKeyDiff(sr, sr->last_inputs);
|
||||
|
||||
if (sr->replay_mode) {
|
||||
// When clearing the key log while in replay mode, we want to keep
|
||||
// replaying but discarding all key history up until this point.
|
||||
|
|
@ -340,7 +324,7 @@ uint16 StateRecorder_ReadNextReplayState(StateRecorder *sr) {
|
|||
// Apply next command
|
||||
sr->frames_since_last = 0;
|
||||
if (sr->replay_cmd < 0xc0) {
|
||||
sr->last_inputs ^= 1 << (sr->replay_cmd >> 4);
|
||||
sr->last_inputs ^= 1 << ((sr->replay_cmd >> 4) + sr->cur_player * 12);
|
||||
} else if (sr->replay_cmd < 0xd0) {
|
||||
int nb = 1 + ((sr->replay_cmd >> 2) & 3);
|
||||
uint8 t;
|
||||
|
|
@ -352,7 +336,6 @@ uint16 StateRecorder_ReadNextReplayState(StateRecorder *sr) {
|
|||
addr |= sr->log.data[replay_pos++];
|
||||
do {
|
||||
g_ram[addr & 0x1ffff] = sr->log.data[replay_pos++];
|
||||
RtlSyncMemoryRegion(&g_ram[addr & 0x1ffff], 1);
|
||||
} while (addr++, --nb);
|
||||
} else {
|
||||
assert(0);
|
||||
|
|
@ -365,7 +348,20 @@ uint16 StateRecorder_ReadNextReplayState(StateRecorder *sr) {
|
|||
break;
|
||||
}
|
||||
// Read the next one
|
||||
uint8 cmd = sr->log.data[replay_pos++], t;
|
||||
uint8 cmd, t;
|
||||
|
||||
for (;;) {
|
||||
cmd = sr->log.data[replay_pos++];
|
||||
if (cmd < 0xfc)
|
||||
break;
|
||||
switch (cmd) {
|
||||
case 0xfc:
|
||||
case 0xfd: sr->cur_player = cmd - 0xfc; break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
int mask = (cmd < 0xc0) ? 0xf : 0x1;
|
||||
int frames = cmd & mask;
|
||||
if (frames == mask) do {
|
||||
|
|
@ -400,7 +396,8 @@ void RtlStopReplay(void) {
|
|||
StateRecorder_StopReplay(&state_recorder);
|
||||
}
|
||||
|
||||
bool RtlRunFrame(int inputs) {
|
||||
bool RtlRunFrame(uint32 inputs) {
|
||||
|
||||
if (g_did_finish_level_hook) {
|
||||
if (game_id == kGameID_SMW && !state_recorder.replay_mode && g_config.save_playthrough) {
|
||||
SmwSavePlaythroughSnapshot();
|
||||
|
|
@ -414,6 +411,9 @@ bool RtlRunFrame(int inputs) {
|
|||
// Avoid up/down and left/right from being pressed at the same time
|
||||
if ((inputs & 0x30) == 0x30) inputs ^= 0x30;
|
||||
if ((inputs & 0xc0) == 0xc0) inputs ^= 0xc0;
|
||||
// Player2
|
||||
if ((inputs & 0x30000) == 0x30000) inputs ^= 0x30000;
|
||||
if ((inputs & 0xc0000) == 0xc0000) inputs ^= 0xc0000;
|
||||
|
||||
bool is_replay = state_recorder.replay_mode;
|
||||
|
||||
|
|
@ -433,12 +433,21 @@ bool RtlRunFrame(int inputs) {
|
|||
uint8 apui02 = RtlApuReadReg(2);
|
||||
if (apui02 != g_ram[kSmwRam_APUI02]) {
|
||||
g_ram[kSmwRam_APUI02] = apui02;
|
||||
StateRecorder_RecordPatchByte(&state_recorder, kSmwRam_APUI02, &apui02, 1);
|
||||
StateRecorder_RecordPatchByte(&state_recorder, &g_ram[kSmwRam_APUI02], 1);
|
||||
}
|
||||
// Whether controllers are plugged in.
|
||||
uint32 new_my_flags = inputs >> 30;
|
||||
if (new_my_flags != g_ram[kSmwRam_my_flags]) {
|
||||
assert(new_my_flags <= 255);
|
||||
g_ram[kSmwRam_my_flags] = new_my_flags;
|
||||
StateRecorder_RecordPatchByte(&state_recorder, &g_ram[kSmwRam_my_flags], 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
g_snes->input1_currentState = inputs & 0xfff;
|
||||
g_snes->input2_currentState = (inputs >> 12) & 0xfff;
|
||||
|
||||
g_rtl_runframe(inputs, 0);
|
||||
RtlRunFrameCompare();
|
||||
|
||||
snes_frame_counter++;
|
||||
|
||||
|
|
@ -462,7 +471,6 @@ static void RtlLoadFromFile(FILE *f, bool replay) {
|
|||
ppu_copy(g_my_ppu, g_snes->ppu);
|
||||
|
||||
RtlApuUnlock();
|
||||
RtlSynchronizeWholeState();
|
||||
}
|
||||
|
||||
static const char *const kBugSaves[] = {
|
||||
|
|
@ -789,7 +797,6 @@ void RtlReadSram(void) {
|
|||
if (fread(g_sram, 1, g_sram_size, f) != g_sram_size)
|
||||
fprintf(stderr, "Error reading %s\n", filename);
|
||||
fclose(f);
|
||||
RtlSynchronizeWholeState();
|
||||
ByteArray_Resize(&state_recorder.base_snapshot, g_sram_size);
|
||||
memcpy(state_recorder.base_snapshot.data, g_sram, g_sram_size);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ enum {
|
|||
kCurrentBugFixCounter = 1,
|
||||
|
||||
kSmwRam_APUI02 = 0x18c5,
|
||||
kSmwRam_my_flags = 0x19C7C,
|
||||
};
|
||||
|
||||
typedef struct SimpleHdma {
|
||||
|
|
@ -103,12 +104,7 @@ uint8 ReadReg(uint16 reg);
|
|||
uint8_t *IndirPtr(LongPtr ptr, uint16 offs);
|
||||
void IndirWriteByte(LongPtr ptr, uint16 offs, uint8 value);
|
||||
|
||||
|
||||
typedef void RunFrameFunc(uint16 input, int run_what);
|
||||
typedef void SyncAllFunc();
|
||||
|
||||
void RtlReset(int mode);
|
||||
void RtlSetupEmuCallbacks(uint8 *emu_ram, RunFrameFunc *func, SyncAllFunc *sync_all);
|
||||
void RtlClearKeyLog();
|
||||
void RtlStopReplay();
|
||||
|
||||
|
|
@ -127,7 +123,7 @@ void RtlSetUploadingApu(bool uploading);
|
|||
void RtlApuUpload(const uint8 *p);
|
||||
void RtlRenderAudio(int16 *audio_buffer, int samples, int channels);
|
||||
void RtlPushApuState();
|
||||
bool RtlRunFrame(int inputs);
|
||||
bool RtlRunFrame(uint32 inputs);
|
||||
void RtlReadSram();
|
||||
void RtlWriteSram();
|
||||
void RtlSaveSnapshot(const char *filename, bool saving_with_bug);
|
||||
|
|
|
|||
40
src/config.c
40
src/config.c
|
|
@ -24,6 +24,8 @@ static const uint16 kDefaultKbdControls[kKeys_Total] = {
|
|||
0,
|
||||
// Controls
|
||||
_(SDLK_UP), _(SDLK_DOWN), _(SDLK_LEFT), _(SDLK_RIGHT), _(SDLK_RSHIFT), _(SDLK_RETURN), _(SDLK_x), _(SDLK_z), _(SDLK_s), _(SDLK_a), _(SDLK_c), _(SDLK_v),
|
||||
// ControlsP2
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
// LoadState
|
||||
_(SDLK_F1), _(SDLK_F2), _(SDLK_F3), _(SDLK_F4), _(SDLK_F5), _(SDLK_F6), _(SDLK_F7), _(SDLK_F8), _(SDLK_F9), _(SDLK_F10), N, N, N, N, N, N, N, N, N, N,
|
||||
// SaveState
|
||||
|
|
@ -56,7 +58,8 @@ typedef struct KeyNameId {
|
|||
#define S(n) {#n, kKeys_##n, 1}
|
||||
static const KeyNameId kKeyNameId[] = {
|
||||
{"Null", kKeys_Null, 65535},
|
||||
M(Controls), M(Load), M(Save), M(Replay), M(LoadRef), M(ReplayRef),
|
||||
M(Controls), M(ControlsP2),
|
||||
M(Load), M(Save), M(Replay), M(LoadRef), M(ReplayRef),
|
||||
S(CheatLife), S(CheatJump), S(ToggleWhichFrame),
|
||||
S(ClearKeyLog), S(StopReplay), S(Fullscreen), S(Reset),
|
||||
S(Pause), S(PauseDimmed), S(Turbo), S(ReplayTurbo), S(WindowBigger), S(WindowSmaller), S(VolumeUp), S(VolumeDown), S(DisplayPerf), S(ToggleRenderer),
|
||||
|
|
@ -73,6 +76,14 @@ static int keymap_hash_size;
|
|||
static bool has_keynameid[countof(kKeyNameId)];
|
||||
|
||||
static bool KeyMapHash_Add(uint16 key, uint16 cmd) {
|
||||
if (!key)
|
||||
return false;
|
||||
|
||||
if (cmd == kKeys_Controls)
|
||||
g_config.has_keyboard_controls |= 1;
|
||||
else if (cmd == kKeys_ControlsP2)
|
||||
g_config.has_keyboard_controls |= 2;
|
||||
|
||||
if ((keymap_hash_size & 0xff) == 0) {
|
||||
if (keymap_hash_size > 10000)
|
||||
Die("Too many keys");
|
||||
|
|
@ -154,10 +165,10 @@ typedef struct GamepadMapEnt {
|
|||
uint16 cmd, next;
|
||||
} GamepadMapEnt;
|
||||
|
||||
static uint16 joymap_first[kGamepadBtn_Count];
|
||||
static uint16 joymap_first[kGamepadBtn_Count * 2]; // 2 gamepads
|
||||
static GamepadMapEnt *joymap_ents;
|
||||
static int joymap_size;
|
||||
static bool has_joypad_controls;
|
||||
static uint8 has_assigned_joypad_controls;
|
||||
|
||||
static int CountBits32(uint32 n) {
|
||||
int count = 0;
|
||||
|
|
@ -224,12 +235,13 @@ static const uint8 kDefaultGamepadCmds[] = {
|
|||
kGamepadBtn_B, kGamepadBtn_A, kGamepadBtn_Y, kGamepadBtn_X, kGamepadBtn_L1, kGamepadBtn_R1,
|
||||
};
|
||||
|
||||
static void ParseGamepadArray(char *value, int cmd, int size) {
|
||||
static void ParseGamepadArray(int gamepad, char *value, int cmd, int size) {
|
||||
char *s;
|
||||
int i = 0;
|
||||
for (; i < size && (s = NextDelim(&value, ',')) != NULL; i++, cmd += (cmd != 0)) {
|
||||
if (*s == 0)
|
||||
continue;
|
||||
int gamepad_cur = gamepad;
|
||||
uint32 modifiers = 0;
|
||||
const char *ss = s;
|
||||
for (;;) {
|
||||
|
|
@ -243,7 +255,7 @@ static void ParseGamepadArray(char *value, int cmd, int size) {
|
|||
ss++;
|
||||
modifiers |= 1 << button;
|
||||
} else if (*ss == 0) {
|
||||
GamepadMap_Add(button, modifiers, cmd);
|
||||
GamepadMap_Add(button + gamepad_cur * kGamepadBtn_Count, modifiers, cmd);
|
||||
break;
|
||||
} else
|
||||
goto BAD;
|
||||
|
|
@ -259,10 +271,14 @@ static void RegisterDefaultKeys(void) {
|
|||
KeyMapHash_Add(kDefaultKbdControls[k], k);
|
||||
}
|
||||
}
|
||||
if (!has_joypad_controls) {
|
||||
if (!(has_assigned_joypad_controls & 1)) {
|
||||
for (int i = 0; i < countof(kDefaultGamepadCmds); i++)
|
||||
GamepadMap_Add(kDefaultGamepadCmds[i], 0, kKeys_Controls + i);
|
||||
}
|
||||
if (!(has_assigned_joypad_controls & 2)) {
|
||||
for (int i = 0; i < countof(kDefaultGamepadCmds); i++)
|
||||
GamepadMap_Add(kDefaultGamepadCmds[i] + kGamepadBtn_Count, 0, kKeys_ControlsP2 + i);
|
||||
}
|
||||
}
|
||||
|
||||
static int GetIniSection(const char *s) {
|
||||
|
|
@ -321,14 +337,20 @@ static bool HandleIniConfig(int section, const char *key, char *value) {
|
|||
}
|
||||
}
|
||||
} else if (section == 5) {
|
||||
if (StringEqualsNoCase(key, "EnableGamepad1")) {
|
||||
return ParseBool(value, &g_config.enable_gamepad[0]);
|
||||
} else if (StringEqualsNoCase(key, "EnableGamepad2")) {
|
||||
return ParseBool(value, &g_config.enable_gamepad[1]);
|
||||
} else {
|
||||
for (int i = 0; i < countof(kKeyNameId); i++) {
|
||||
if (StringEqualsNoCase(key, kKeyNameId[i].name)) {
|
||||
if (i == 1)
|
||||
has_joypad_controls = true;
|
||||
ParseGamepadArray(value, kKeyNameId[i].id, kKeyNameId[i].size);
|
||||
int id = kKeyNameId[i].id;
|
||||
has_assigned_joypad_controls |= (id == kKeys_Controls) ? 1 : (id == kKeys_ControlsP2) ? 2 : 0;
|
||||
ParseGamepadArray(id == kKeys_ControlsP2 ? 1 : 0, value, kKeyNameId[i].id, kKeyNameId[i].size);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (section == 1) {
|
||||
if (StringEqualsNoCase(key, "WindowSize")) {
|
||||
char *s;
|
||||
|
|
|
|||
|
|
@ -6,6 +6,10 @@ enum {
|
|||
kKeys_Null,
|
||||
kKeys_Controls,
|
||||
kKeys_Controls_Last = kKeys_Controls + 11,
|
||||
|
||||
kKeys_ControlsP2,
|
||||
kKeys_ControlsP2_Last = kKeys_ControlsP2 + 11,
|
||||
|
||||
kKeys_Load,
|
||||
kKeys_Load_Last = kKeys_Load + 19,
|
||||
kKeys_Save,
|
||||
|
|
@ -72,6 +76,11 @@ typedef struct Config {
|
|||
char *memory_buffer;
|
||||
const char *shader;
|
||||
const char *msu_path;
|
||||
|
||||
bool enable_gamepad[2];
|
||||
|
||||
// Which players have keyboard controls
|
||||
uint8 has_keyboard_controls;
|
||||
} Config;
|
||||
|
||||
enum {
|
||||
|
|
|
|||
141
src/main.c
141
src/main.c
|
|
@ -31,15 +31,26 @@
|
|||
|
||||
#include "assets/smw_assets.h"
|
||||
|
||||
typedef struct GamepadInfo {
|
||||
uint32 modifiers;
|
||||
SDL_JoystickID joystick_id;
|
||||
uint8 index;
|
||||
uint8 axis_buttons;
|
||||
uint16 last_cmd[kGamepadBtn_Count];
|
||||
Sint16 last_axis_x, last_axis_y;
|
||||
} GamepadInfo;
|
||||
|
||||
|
||||
static void SDLCALL AudioCallback(void *userdata, Uint8 *stream, int len);
|
||||
static void LoadAssets();
|
||||
static void SwitchDirectory();
|
||||
static void RenderNumber(uint8 *dst, size_t pitch, int n, uint8 big);
|
||||
static void OpenOneGamepad(int i);
|
||||
static uint32 GetActiveControllers(void);
|
||||
static void HandleVolumeAdjustment(int volume_adjustment);
|
||||
static void HandleGamepadAxisInput(int gamepad_id, int axis, int value);
|
||||
static void HandleGamepadAxisInput(GamepadInfo *gi, int axis, Sint16 value);
|
||||
static int RemapSdlButton(int button);
|
||||
static void HandleGamepadInput(int button, bool pressed);
|
||||
static void HandleGamepadInput(GamepadInfo *gi, int button, bool pressed);
|
||||
static void HandleInput(int keyCode, int keyMod, bool pressed);
|
||||
static void HandleCommand(uint32 j, bool pressed);
|
||||
void OpenGLRenderer_Create(struct RendererFuncs *funcs);
|
||||
|
|
@ -49,7 +60,6 @@ bool g_want_dump_memmap_flags;
|
|||
bool g_new_ppu = true;
|
||||
bool g_other_image = true;
|
||||
struct SpcPlayer *g_spc_player;
|
||||
static uint32_t button_state;
|
||||
|
||||
static uint8_t g_pixels[256 * 4 * 240];
|
||||
static uint8_t g_my_pixels[256 * 4 * 240];
|
||||
|
|
@ -70,16 +80,16 @@ static SDL_Window *g_window;
|
|||
|
||||
static uint8 g_paused, g_turbo, g_replay_turbo = true, g_cursor = true;
|
||||
static uint8 g_current_window_scale;
|
||||
static uint8 g_gamepad_buttons;
|
||||
static int g_input1_state;
|
||||
static uint32 g_input_state;
|
||||
static bool g_display_perf;
|
||||
static int g_curr_fps;
|
||||
static int g_ppu_render_flags = 0;
|
||||
static int g_snes_width, g_snes_height;
|
||||
static int g_sdl_audio_mixer_volume = SDL_MIX_MAXVOLUME;
|
||||
static struct RendererFuncs g_renderer_funcs;
|
||||
static uint32 g_gamepad_modifiers;
|
||||
static uint16 g_gamepad_last_cmd[kGamepadBtn_Count];
|
||||
|
||||
static GamepadInfo g_gamepad[2];
|
||||
|
||||
extern Snes *g_snes;
|
||||
|
||||
void NORETURN Die(const char *error) {
|
||||
|
|
@ -93,6 +103,10 @@ void Warning(const char *error) {
|
|||
fprintf(stderr, "Warning: %s\n", error);
|
||||
}
|
||||
|
||||
static GamepadInfo *GetGamepadInfo(SDL_JoystickID id) {
|
||||
return (g_gamepad[0].joystick_id == id) ? &g_gamepad[0] :
|
||||
(g_gamepad[1].joystick_id == id) ? &g_gamepad[1] : NULL;
|
||||
}
|
||||
|
||||
void ChangeWindowScale(int scale_step) {
|
||||
if ((SDL_GetWindowFlags(g_window) & (SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_FULLSCREEN | SDL_WINDOW_MINIMIZED | SDL_WINDOW_MAXIMIZED)) != 0)
|
||||
|
|
@ -340,6 +354,7 @@ int main(int argc, char** argv) {
|
|||
|
||||
LoadAssets();
|
||||
|
||||
g_gamepad[0].joystick_id = g_gamepad[1].joystick_id = -1;
|
||||
g_snes_width = (g_config.extended_aspect_ratio * 2 + 256);
|
||||
g_snes_height = 224;// (g_config.extend_y ? 240 : 224);
|
||||
g_ppu_render_flags = g_config.new_renderer * kPpuRenderFlags_NewRenderer |
|
||||
|
|
@ -466,6 +481,7 @@ error_reading:;
|
|||
uint32 frameCtr = 0;
|
||||
uint8 audiopaused = true;
|
||||
bool has_bug_in_title = false;
|
||||
GamepadInfo *gi;
|
||||
|
||||
while (running) {
|
||||
SDL_Event event;
|
||||
|
|
@ -475,14 +491,26 @@ error_reading:;
|
|||
case SDL_CONTROLLERDEVICEADDED:
|
||||
OpenOneGamepad(event.cdevice.which);
|
||||
break;
|
||||
case SDL_CONTROLLERDEVICEREMOVED:
|
||||
gi = GetGamepadInfo(event.cdevice.which);
|
||||
if (gi) {
|
||||
memset(gi, 0, sizeof(GamepadInfo));
|
||||
gi->joystick_id = -1;
|
||||
}
|
||||
break;
|
||||
case SDL_CONTROLLERAXISMOTION:
|
||||
HandleGamepadAxisInput(event.caxis.which, event.caxis.axis, event.caxis.value);
|
||||
gi = GetGamepadInfo(event.caxis.which);
|
||||
if (gi)
|
||||
HandleGamepadAxisInput(gi, event.caxis.axis, event.caxis.value);
|
||||
break;
|
||||
case SDL_CONTROLLERBUTTONDOWN:
|
||||
case SDL_CONTROLLERBUTTONUP: {
|
||||
gi = GetGamepadInfo(event.cbutton.which);
|
||||
if (gi) {
|
||||
int b = RemapSdlButton(event.cbutton.button);
|
||||
if (b >= 0)
|
||||
HandleGamepadInput(b, event.type == SDL_CONTROLLERBUTTONDOWN);
|
||||
HandleGamepadInput(gi, b, event.type == SDL_CONTROLLERBUTTONDOWN);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SDL_MOUSEWHEEL:
|
||||
|
|
@ -521,12 +549,12 @@ error_reading:;
|
|||
}
|
||||
|
||||
// Clear gamepad inputs when joypad directional inputs to avoid wonkiness
|
||||
int inputs = g_input1_state;
|
||||
if (g_input1_state & 0xf0)
|
||||
g_gamepad_buttons = 0;
|
||||
inputs |= g_gamepad_buttons;
|
||||
|
||||
uint8 is_replay = RtlRunFrame(inputs);
|
||||
if (g_input_state & 0xf0)
|
||||
g_gamepad[0].axis_buttons = 0;
|
||||
if (g_input_state & 0xf0000)
|
||||
g_gamepad[1].axis_buttons = 0;
|
||||
uint32 inputs = g_input_state | g_gamepad[0].axis_buttons | g_gamepad[1].axis_buttons << 12;
|
||||
uint8 is_replay = RtlRunFrame(inputs | GetActiveControllers());
|
||||
|
||||
frameCtr++;
|
||||
g_snes->disableRender = (g_turbo ^ (is_replay & g_replay_turbo)) && (frameCtr & (g_turbo ? 0xf : 0x7f)) != 0;
|
||||
|
|
@ -634,12 +662,19 @@ static void RenderNumber(uint8 *dst, size_t pitch, int n, uint8 big) {
|
|||
}
|
||||
|
||||
static void HandleCommand(uint32 j, bool pressed) {
|
||||
static const uint8 kKbdRemap[] = { 4, 5, 6, 7, 2, 3, 8, 0, 9, 1, 10, 11 };
|
||||
if (j < kKeys_Controls)
|
||||
return;
|
||||
|
||||
if (j <= kKeys_Controls_Last) {
|
||||
static const uint8 kKbdRemap[] = { 0, 4, 5, 6, 7, 2, 3, 8, 0, 9, 1, 10, 11 };
|
||||
if (pressed)
|
||||
g_input1_state |= 1 << kKbdRemap[j];
|
||||
else
|
||||
g_input1_state &= ~(1 << kKbdRemap[j]);
|
||||
uint32 m = 1 << kKbdRemap[j - kKeys_Controls];
|
||||
g_input_state = pressed ? (g_input_state | m) : (g_input_state & ~m);
|
||||
return;
|
||||
}
|
||||
|
||||
if (j <= kKeys_ControlsP2_Last) {
|
||||
uint32 m = 0x1000 << kKbdRemap[j - kKeys_ControlsP2];
|
||||
g_input_state = pressed ? (g_input_state | m) : (g_input_state & ~m);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -715,11 +750,43 @@ static void HandleInput(int keyCode, int keyMod, bool pressed) {
|
|||
HandleCommand(j, pressed);
|
||||
}
|
||||
|
||||
static uint32 GetActiveControllers() {
|
||||
uint32 ctrl = g_config.has_keyboard_controls;
|
||||
ctrl |= g_gamepad[0].joystick_id != -1 ? 1 : 0;
|
||||
ctrl |= g_gamepad[1].joystick_id != -1 ? 2 : 0;
|
||||
return ctrl << 30;
|
||||
}
|
||||
|
||||
static void OpenOneGamepad(int i) {
|
||||
if (SDL_IsGameController(i)) {
|
||||
SDL_GameController *controller = SDL_GameControllerOpen(i);
|
||||
if (!controller)
|
||||
if (!controller) {
|
||||
fprintf(stderr, "Could not open gamepad %d: %s\n", i, SDL_GetError());
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 joystick_id = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(controller));
|
||||
if (GetGamepadInfo(joystick_id))
|
||||
return;
|
||||
|
||||
uint8 scan_order[3] = { SDL_GameControllerGetPlayerIndex(controller), 0, 1 };
|
||||
|
||||
int found_idx = -1;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
uint8 j = scan_order[i];
|
||||
if (j < 2 && g_config.enable_gamepad[j] && (i == 0 || g_gamepad[j].joystick_id == -1)) {
|
||||
found_idx = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
printf("Found controller '%s' assigning to player %d\n", SDL_GameControllerName(controller), found_idx + 1);
|
||||
if (found_idx >= 0) {
|
||||
GamepadInfo *gi = &g_gamepad[found_idx];
|
||||
memset(gi, 0, sizeof(GamepadInfo));
|
||||
gi->index = found_idx;
|
||||
gi->joystick_id = joystick_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -744,14 +811,14 @@ static int RemapSdlButton(int button) {
|
|||
}
|
||||
}
|
||||
|
||||
static void HandleGamepadInput(int button, bool pressed) {
|
||||
if (!!(g_gamepad_modifiers & (1 << button)) == pressed)
|
||||
static void HandleGamepadInput(GamepadInfo *gi, int button, bool pressed) {
|
||||
if (!!(gi->modifiers & (1 << button)) == pressed)
|
||||
return;
|
||||
g_gamepad_modifiers ^= 1 << button;
|
||||
gi->modifiers ^= 1 << button;
|
||||
if (pressed)
|
||||
g_gamepad_last_cmd[button] = FindCmdForGamepadButton(button, g_gamepad_modifiers);
|
||||
if (g_gamepad_last_cmd[button] != 0)
|
||||
HandleCommand(g_gamepad_last_cmd[button], pressed);
|
||||
gi->last_cmd[button] = FindCmdForGamepadButton(button + gi->index * kGamepadBtn_Count, gi->modifiers);
|
||||
if (gi->last_cmd[button] != 0)
|
||||
HandleCommand(gi->last_cmd[button], pressed);
|
||||
}
|
||||
|
||||
static void HandleVolumeAdjustment(int volume_adjustment) {
|
||||
|
|
@ -787,19 +854,11 @@ static float ApproximateAtan2(float y, float x) {
|
|||
return q + *(float *)&uatan_2q;
|
||||
}
|
||||
|
||||
static void HandleGamepadAxisInput(int gamepad_id, int axis, int value) {
|
||||
static int last_gamepad_id, last_x, last_y;
|
||||
static void HandleGamepadAxisInput(GamepadInfo *gi, int axis, Sint16 value) {
|
||||
if (axis == SDL_CONTROLLER_AXIS_LEFTX || axis == SDL_CONTROLLER_AXIS_LEFTY) {
|
||||
// ignore other gamepads unless they have a big input
|
||||
if (last_gamepad_id != gamepad_id) {
|
||||
if (value > -16000 && value < 16000)
|
||||
return;
|
||||
last_gamepad_id = gamepad_id;
|
||||
last_x = last_y = 0;
|
||||
}
|
||||
*(axis == SDL_CONTROLLER_AXIS_LEFTX ? &last_x : &last_y) = value;
|
||||
*(axis == SDL_CONTROLLER_AXIS_LEFTX ? &gi->last_axis_x : &gi->last_axis_y) = value;
|
||||
int buttons = 0;
|
||||
if (last_x * last_x + last_y * last_y >= 10000 * 10000) {
|
||||
if (gi->last_axis_x * gi->last_axis_x + gi->last_axis_y * gi->last_axis_y >= 10000 * 10000) {
|
||||
// in the non deadzone part, divide the circle into eight 45 degree
|
||||
// segments rotated by 22.5 degrees that control which direction to move.
|
||||
// todo: do this without floats?
|
||||
|
|
@ -813,13 +872,13 @@ static void HandleGamepadAxisInput(int gamepad_id, int axis, int value) {
|
|||
1 << 6, // 6 = left
|
||||
1 << 6 | 1 << 4, // 7 = left, up
|
||||
};
|
||||
uint8 angle = (uint8)(int)(ApproximateAtan2(last_y, last_x) * 64.0f + 0.5f);
|
||||
uint8 angle = (uint8)(int)(ApproximateAtan2(gi->last_axis_y, gi->last_axis_x) * 64.0f + 0.5f);
|
||||
buttons = kSegmentToButtons[(uint8)(angle + 16 + 64) >> 5];
|
||||
}
|
||||
g_gamepad_buttons = buttons;
|
||||
gi->axis_buttons = buttons;
|
||||
} else if ((axis == SDL_CONTROLLER_AXIS_TRIGGERLEFT || axis == SDL_CONTROLLER_AXIS_TRIGGERRIGHT)) {
|
||||
if (value < 12000 || value >= 16000) // hysteresis
|
||||
HandleGamepadInput(axis == SDL_CONTROLLER_AXIS_TRIGGERLEFT ? kGamepadBtn_L2 : kGamepadBtn_R2, value >= 12000);
|
||||
HandleGamepadInput(gi, axis == SDL_CONTROLLER_AXIS_TRIGGERLEFT ? kGamepadBtn_L2 : kGamepadBtn_R2, value >= 12000);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -199,10 +199,6 @@
|
|||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
|
||||
</ClCompile>
|
||||
<ClCompile Include="snes\input.c">
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">MinSpace</Optimization>
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">MinSpace</Optimization>
|
||||
</ClCompile>
|
||||
<ClCompile Include="snes\ppu.c">
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
|
||||
|
|
@ -241,7 +237,6 @@
|
|||
<ClInclude Include="snes\dma.h" />
|
||||
<ClInclude Include="snes\dsp.h" />
|
||||
<ClInclude Include="snes\dsp_regs.h" />
|
||||
<ClInclude Include="snes\input.h" />
|
||||
<ClInclude Include="snes\ppu.h" />
|
||||
<ClInclude Include="snes\saveload.h" />
|
||||
<ClInclude Include="snes\snes.h" />
|
||||
|
|
|
|||
11
src/smw_00.c
11
src/smw_00.c
|
|
@ -1587,14 +1587,9 @@ void GameMode12_PrepareLevel_009A3D(uint8 k) { // 009a3d
|
|||
}
|
||||
|
||||
void CheckWhichControllersArePluggedIn() { // 009a74
|
||||
uint8 v1 = ReadReg(JOYA);
|
||||
uint8 Reg = ReadReg(JOYB);
|
||||
uint8 v2 = (2 * Reg + v1) & 3;
|
||||
if (v2) {
|
||||
if (v2 == 3)
|
||||
v2 = -125;
|
||||
--v2;
|
||||
}
|
||||
uint8 v2 = my_flags & 3;
|
||||
if (v2)
|
||||
v2 += ((v2 == 3) ? 0x80 : 0) - 1;
|
||||
io_controllers_plugged_in = v2;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -82,6 +82,10 @@ uint32 PatchBugs_SMW1(void) {
|
|||
} else if (FixBugHook(0x4e686)) {
|
||||
// CheckIfDestroyTileEventIsActive doesn't zero Y
|
||||
g_cpu->y = 0;
|
||||
} else if (FixBugHook(0x9A74)) {
|
||||
CheckWhichControllersArePluggedIn();
|
||||
// Remove old CheckWhichControllersArePluggedIn
|
||||
return 0x9A8A;
|
||||
} else if (FixBugHook(0x058AFB) || FixBugHook(0x58CE0)) {
|
||||
|
||||
int lvl_setting = misc_level_mode_setting;
|
||||
|
|
|
|||
|
|
@ -1,42 +0,0 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "input.h"
|
||||
#include "snes.h"
|
||||
|
||||
Input* input_init(Snes* snes) {
|
||||
Input* input = malloc(sizeof(Input));
|
||||
input->snes = snes;
|
||||
// TODO: handle (where?)
|
||||
input->type = 1;
|
||||
input->currentState = 0;
|
||||
return input;
|
||||
}
|
||||
|
||||
void input_free(Input* input) {
|
||||
free(input);
|
||||
}
|
||||
|
||||
void input_reset(Input* input) {
|
||||
input->latchLine = false;
|
||||
input->latchedState = 0;
|
||||
}
|
||||
|
||||
void input_cycle(Input *input) {
|
||||
if (input->latchLine) {
|
||||
input->latchedState = input->currentState;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t input_read(Input *input) {
|
||||
uint8_t ret = input->latchedState & 1;
|
||||
input->latchedState >>= 1;
|
||||
input->latchedState |= 0x8000;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
|
||||
#ifndef INPUT_H
|
||||
#define INPUT_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct Input Input;
|
||||
|
||||
#include "snes.h"
|
||||
|
||||
struct Input {
|
||||
Snes *snes;
|
||||
uint8_t type;
|
||||
// latchline
|
||||
bool latchLine;
|
||||
// for controller
|
||||
uint16_t currentState; // actual state
|
||||
uint16_t latchedState;
|
||||
};
|
||||
|
||||
Input* input_init(Snes* snes);
|
||||
void input_free(Input* input);
|
||||
void input_reset(Input* input);
|
||||
void input_cycle(Input *input);
|
||||
uint8_t input_read(Input *input);
|
||||
|
||||
#endif
|
||||
|
|
@ -12,7 +12,6 @@
|
|||
#include "dma.h"
|
||||
#include "ppu.h"
|
||||
#include "cart.h"
|
||||
#include "input.h"
|
||||
#include "../tracing.h"
|
||||
#include "../variables.h"
|
||||
#include "../common_rtl.h"
|
||||
|
|
@ -38,8 +37,8 @@ Snes* snes_init(uint8_t *ram) {
|
|||
snes->dma = dma_init(snes);
|
||||
snes->ppu = ppu_init();
|
||||
snes->cart = cart_init(snes);
|
||||
snes->input1 = input_init(snes);
|
||||
snes->input2 = input_init(snes);
|
||||
snes->input1_currentState = 0;
|
||||
snes->input2_currentState = 0;
|
||||
return snes;
|
||||
}
|
||||
|
||||
|
|
@ -49,8 +48,6 @@ void snes_free(Snes* snes) {
|
|||
dma_free(snes->dma);
|
||||
ppu_free(snes->ppu);
|
||||
cart_free(snes->cart);
|
||||
input_free(snes->input1);
|
||||
input_free(snes->input2);
|
||||
free(snes);
|
||||
}
|
||||
|
||||
|
|
@ -75,8 +72,6 @@ void snes_reset(Snes* snes, bool hard) {
|
|||
apu_reset(snes->apu);
|
||||
dma_reset(snes->dma);
|
||||
ppu_reset(snes->ppu);
|
||||
input_reset(snes->input1);
|
||||
input_reset(snes->input2);
|
||||
if (hard)
|
||||
memset(snes->ram, 0, 0x20000);
|
||||
snes->ramAdr = 0;
|
||||
|
|
@ -106,19 +101,6 @@ void snes_reset(Snes* snes, bool hard) {
|
|||
snes->openBus = 0;
|
||||
}
|
||||
|
||||
void snes_runFrame(Snes *snes) {
|
||||
snes_frame_counter++;
|
||||
|
||||
bool old = true;
|
||||
for (;;) {
|
||||
snes_runCycle(snes);
|
||||
if (snes->inVblank != 0 && snes->inVblank != old) {
|
||||
break;
|
||||
}
|
||||
old = snes->inVblank;
|
||||
}
|
||||
}
|
||||
|
||||
void snes_handle_pos_stuff(Snes *snes) {
|
||||
// check for h/v timer irq's
|
||||
if (snes->vIrqEnabled && snes->hIrqEnabled) {
|
||||
|
|
@ -193,19 +175,6 @@ void snes_handle_pos_stuff(Snes *snes) {
|
|||
}
|
||||
}
|
||||
|
||||
void snes_runCycle(Snes* snes) {
|
||||
snes->apuCatchupCycles += apuCyclesPerMaster * 2.0;
|
||||
|
||||
input_cycle(snes->input1);
|
||||
input_cycle(snes->input2);
|
||||
|
||||
// if not in dram refresh, if we are busy with hdma/dma, do that, else do cpu cycle
|
||||
if (snes->hPos < 536 || snes->hPos >= 576) {
|
||||
snes_runCpu(snes);
|
||||
}
|
||||
|
||||
snes_handle_pos_stuff(snes);
|
||||
}
|
||||
#define IS_ADR(x) (x == 0xfffff)
|
||||
|
||||
void snes_runCpu(Snes *snes) {
|
||||
|
|
@ -323,13 +292,15 @@ static uint8_t snes_readReg(Snes* snes, uint16_t adr) {
|
|||
case 0x4217:
|
||||
return snes->multiplyResult >> 8;
|
||||
case 0x4218:
|
||||
return SwapInputBits(snes->input1->currentState) & 0xff;
|
||||
return SwapInputBits(snes->input1_currentState) & 0xff;
|
||||
case 0x4219:
|
||||
return SwapInputBits(snes->input1->currentState) >> 8;
|
||||
return SwapInputBits(snes->input1_currentState) >> 8;
|
||||
case 0x421a:
|
||||
return SwapInputBits(snes->input2_currentState) & 0xff;
|
||||
case 0x421b:
|
||||
return SwapInputBits(snes->input2_currentState) >> 8;
|
||||
case 0x421c:
|
||||
case 0x421e:
|
||||
case 0x421b:
|
||||
case 0x421d:
|
||||
case 0x421f:
|
||||
return 0;
|
||||
|
|
@ -447,7 +418,8 @@ uint8_t snes_read(Snes* snes, uint32_t adr) {
|
|||
return snes_readBBus(snes, adr & 0xff); // B-bus
|
||||
}
|
||||
if (adr == 0x4016 || adr == 0x4017) {
|
||||
return input_read(snes->input1) | (snes->openBus & 0xfc);
|
||||
// joypad read disabled
|
||||
return 0;
|
||||
}
|
||||
if(adr >= 0x4200 && adr < 0x4220 || adr >= 0x4218 && adr < 0x4220) {
|
||||
return snes_readReg(snes, adr); // internal registers
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ typedef struct Snes Snes;
|
|||
#include "dma.h"
|
||||
#include "ppu.h"
|
||||
#include "cart.h"
|
||||
#include "input.h"
|
||||
#include "saveload.h"
|
||||
|
||||
struct Snes {
|
||||
|
|
@ -24,8 +23,8 @@ struct Snes {
|
|||
Ppu* ppu;
|
||||
Dma* dma;
|
||||
Cart* cart;
|
||||
Input *input1;
|
||||
Input *input2;
|
||||
uint16 input1_currentState;
|
||||
uint16 input2_currentState;
|
||||
// input
|
||||
bool debug_cycles;
|
||||
bool debug_apu_cycles;
|
||||
|
|
@ -73,7 +72,6 @@ struct Snes {
|
|||
Snes* snes_init(uint8_t *ram);
|
||||
void snes_free(Snes* snes);
|
||||
void snes_reset(Snes* snes, bool hard);
|
||||
void snes_runFrame(Snes* snes);
|
||||
// used by dma, cpu
|
||||
uint8_t snes_readBBus(Snes* snes, uint8_t adr);
|
||||
void snes_writeBBus(Snes* snes, uint8_t adr, uint8_t val);
|
||||
|
|
|
|||
|
|
@ -877,6 +877,9 @@ extern uint8 ptr_layer2_is_bg;
|
|||
#define stripe_image_upload_data ((uint8*)(g_ram+0x1837D))
|
||||
#define graphics_decompressed_loading_letters ((uint8*)(g_ram+0x1977B))
|
||||
#define spr86_wiggler_segment_pos_table ((uint8*)(g_ram+0x19A7B))
|
||||
|
||||
#define my_flags (*(uint8*)(g_ram+0x19C7C))
|
||||
|
||||
#define blocks_map16_table_hi ((uint8*)(g_ram+0x1C800))
|
||||
|
||||
#define lm_ptr0 (*(LongPtr*)(g_ram + 0x1c000))
|
||||
|
|
|
|||
Loading…
Reference in New Issue