mirror of https://github.com/mgba-emu/mgba.git
Merge branch 'master' (early part) into medusa
This commit is contained in:
commit
690f716df5
3
CHANGES
3
CHANGES
|
@ -48,6 +48,9 @@ Emulation fixes:
|
|||
- GBA Audio: Fix improperly deserializing GB audio registers (fixes mgba.io/i/2793)
|
||||
- GBA Memory: Make VRAM access stalls only apply to BG RAM
|
||||
- GBA SIO: Fix SIOCNT SI pin value after attaching player 2 (fixes mgba.io/i/2805)
|
||||
- GBA SIO: Fix unconnected normal mode SIOCNT SI bit (fixes mgba.io/i/2810)
|
||||
- GBA SIO: Normal mode transfers with no clock should not finish (fixes mgba.io/i/2811)
|
||||
- GBA Timers: Cascading timers don't tick when disabled (fixes mgba.io/i/2812)
|
||||
- GBA Video: Disable BG target 1 blending when OBJ blending (fixes mgba.io/i/2722)
|
||||
Other fixes:
|
||||
- Core: Allow sending thread requests to a crashed core (fixes mgba.io/i/2784)
|
||||
|
|
|
@ -110,13 +110,13 @@ typedef intptr_t ssize_t;
|
|||
#define ATOMIC_LOAD_PTR(DST, SRC) DST = InterlockedCompareExchangePointer(&SRC, 0, 0)
|
||||
#else
|
||||
// TODO
|
||||
#define ATOMIC_STORE(DST, SRC) DST = SRC
|
||||
#define ATOMIC_LOAD(DST, SRC) DST = SRC
|
||||
#define ATOMIC_ADD(DST, OP) DST += OP
|
||||
#define ATOMIC_SUB(DST, OP) DST -= OP
|
||||
#define ATOMIC_OR(DST, OP) DST |= OP
|
||||
#define ATOMIC_AND(DST, OP) DST &= OP
|
||||
#define ATOMIC_CMPXCHG(DST, EXPECTED, OP) ((DST == EXPECTED) ? ((DST = OP), true) : false)
|
||||
#define ATOMIC_STORE(DST, SRC) ((DST) = (SRC))
|
||||
#define ATOMIC_LOAD(DST, SRC) ((DST) = (SRC))
|
||||
#define ATOMIC_ADD(DST, OP) ((DST) += (OP))
|
||||
#define ATOMIC_SUB(DST, OP) ((DST) -= (OP))
|
||||
#define ATOMIC_OR(DST, OP) ((DST) |= (OP))
|
||||
#define ATOMIC_AND(DST, OP) ((DST) &= (OP))
|
||||
#define ATOMIC_CMPXCHG(DST, EXPECTED, OP) (((DST) == (EXPECTED)) ? (((DST) = (OP)), true) : false)
|
||||
#define ATOMIC_STORE_PTR(DST, SRC) ATOMIC_STORE(DST, SRC)
|
||||
#define ATOMIC_LOAD_PTR(DST, SRC) ATOMIC_LOAD(DST, SRC)
|
||||
#endif
|
||||
|
|
|
@ -249,6 +249,7 @@ mSCRIPT_DECLARE_STRUCT(mScriptGamepad);
|
|||
void mScriptContextAttachInput(struct mScriptContext* context);
|
||||
|
||||
void mScriptContextFireEvent(struct mScriptContext*, struct mScriptEvent*);
|
||||
void mScriptContextClearKeys(struct mScriptContext*);
|
||||
|
||||
int mScriptContextGamepadAttach(struct mScriptContext*, struct mScriptGamepad*);
|
||||
bool mScriptContextGamepadDetach(struct mScriptContext*, int pad);
|
||||
|
|
|
@ -127,7 +127,11 @@ bool GBASIOLockstepNodeLoad(struct GBASIODriver* driver) {
|
|||
break;
|
||||
case SIO_NORMAL_8:
|
||||
case SIO_NORMAL_32:
|
||||
ATOMIC_ADD(node->p->attachedNormal, 1);
|
||||
if (ATOMIC_ADD(node->p->attachedNormal, 1) > node->id + 1 && node->id < 3) {
|
||||
node->d.p->siocnt = GBASIONormalSetSi(node->d.p->siocnt, GBASIONormalGetIdleSo(node->p->players[node->id + 1]->d.p->siocnt));
|
||||
} else {
|
||||
node->d.p->siocnt = GBASIONormalFillSi(node->d.p->siocnt);
|
||||
}
|
||||
node->d.writeRegister = GBASIOLockstepNodeNormalWriteRegister;
|
||||
break;
|
||||
default:
|
||||
|
@ -507,11 +511,28 @@ static uint16_t GBASIOLockstepNodeNormalWriteRegister(struct GBASIODriver* drive
|
|||
|
||||
if (address == REG_SIOCNT) {
|
||||
mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIOCNT <- %04X", node->id, value);
|
||||
int attached;
|
||||
ATOMIC_LOAD(attached, node->p->attachedNormal);
|
||||
value &= 0xFF8B;
|
||||
if (!node->id) {
|
||||
value = GBASIONormalClearSi(value);
|
||||
if (node->id < 3 && attached > node->id + 1) {
|
||||
value = GBASIONormalSetSi(value, GBASIONormalGetIdleSo(node->p->players[node->id + 1]->d.p->siocnt));
|
||||
} else {
|
||||
value = GBASIONormalFillSi(value);
|
||||
}
|
||||
if (value & 0x0080) {
|
||||
|
||||
enum mLockstepPhase transferActive;
|
||||
ATOMIC_LOAD(transferActive, node->p->d.transferActive);
|
||||
if (node->id > 0 && transferActive == TRANSFER_IDLE) {
|
||||
int try;
|
||||
for (try = 0; try < 3; ++try) {
|
||||
GBASIONormal parentSiocnt;
|
||||
ATOMIC_LOAD(parentSiocnt, node->p->players[node->id - 1]->d.p->siocnt);
|
||||
if (ATOMIC_CMPXCHG(node->p->players[node->id - 1]->d.p->siocnt, parentSiocnt, GBASIONormalSetSi(parentSiocnt, GBASIONormalGetIdleSo(value)))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((value & 0x0081) == 0x0081) {
|
||||
if (!node->id) {
|
||||
// Frequency
|
||||
int32_t cycles;
|
||||
|
@ -524,9 +545,6 @@ static uint16_t GBASIOLockstepNodeNormalWriteRegister(struct GBASIODriver* drive
|
|||
cycles *= 4;
|
||||
}
|
||||
|
||||
enum mLockstepPhase transferActive;
|
||||
ATOMIC_LOAD(transferActive, node->p->d.transferActive);
|
||||
|
||||
if (transferActive == TRANSFER_IDLE) {
|
||||
mLOG(GBA_SIO, DEBUG, "Lockstep %i: Transfer initiated", node->id);
|
||||
ATOMIC_STORE(node->p->d.transferActive, TRANSFER_STARTING);
|
||||
|
@ -541,7 +559,7 @@ static uint16_t GBASIOLockstepNodeNormalWriteRegister(struct GBASIODriver* drive
|
|||
value &= ~0x0080;
|
||||
}
|
||||
} else {
|
||||
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
} else if (address == REG_SIODATA32_LO) {
|
||||
|
|
|
@ -37,7 +37,7 @@ static void GBATimerUpdateAudio(struct GBA* gba, int timerId, uint32_t cyclesLat
|
|||
}
|
||||
|
||||
bool GBATimerUpdateCountUp(struct mTiming* timing, struct GBATimer* nextTimer, uint16_t* io, uint32_t cyclesLate) {
|
||||
if (GBATimerFlagsIsCountUp(nextTimer->flags)) { // TODO: Does this increment while disabled?
|
||||
if (GBATimerFlagsIsCountUp(nextTimer->flags) && GBATimerFlagsIsEnable(nextTimer->flags)) {
|
||||
++*io;
|
||||
if (!*io && GBATimerFlagsIsEnable(nextTimer->flags)) {
|
||||
GBATimerUpdate(timing, nextTimer, io, cyclesLate);
|
||||
|
|
|
@ -155,6 +155,10 @@ void ScriptingController::event(QObject* obj, QEvent* event) {
|
|||
}
|
||||
|
||||
switch (event->type()) {
|
||||
case QEvent::FocusOut:
|
||||
case QEvent::WindowDeactivate:
|
||||
mScriptContextClearKeys(&m_scriptContext);
|
||||
return;
|
||||
case QEvent::KeyPress:
|
||||
case QEvent::KeyRelease: {
|
||||
struct mScriptKeyEvent ev{mSCRIPT_EV_TYPE_KEY};
|
||||
|
|
|
@ -427,6 +427,44 @@ void mScriptContextFireEvent(struct mScriptContext* context, struct mScriptEvent
|
|||
mScriptListDeinit(&args);
|
||||
}
|
||||
|
||||
void mScriptContextClearKeys(struct mScriptContext* context) {
|
||||
struct mScriptValue* input = mScriptContextGetGlobal(context, "input");
|
||||
if (!input) {
|
||||
return;
|
||||
}
|
||||
struct mScriptInputContext* inputContext = input->value.opaque;
|
||||
size_t keyCount = TableSize(&inputContext->activeKeys);
|
||||
uint32_t* keys = calloc(keyCount, sizeof(uint32_t));
|
||||
struct TableIterator iter;
|
||||
size_t i = 0;
|
||||
if (!TableIteratorStart(&inputContext->activeKeys, &iter)) {
|
||||
free(keys);
|
||||
return;
|
||||
}
|
||||
do {
|
||||
keys[i] = TableIteratorGetKey(&inputContext->activeKeys, &iter);
|
||||
++i;
|
||||
} while (TableIteratorNext(&inputContext->activeKeys, &iter));
|
||||
|
||||
struct mScriptKeyEvent event = {
|
||||
.d = {
|
||||
.type = mSCRIPT_EV_TYPE_KEY
|
||||
},
|
||||
.state = mSCRIPT_INPUT_STATE_UP,
|
||||
.modifiers = 0
|
||||
};
|
||||
for (i = 0; i < keyCount; ++i) {
|
||||
event.key = keys[i];
|
||||
intptr_t value = (intptr_t) TableLookup(&inputContext->activeKeys, event.key);
|
||||
if (value > 1) {
|
||||
TableInsert(&inputContext->activeKeys, event.key, (void*) 1);
|
||||
}
|
||||
mScriptContextFireEvent(context, &event.d);
|
||||
}
|
||||
|
||||
free(keys);
|
||||
}
|
||||
|
||||
int mScriptContextGamepadAttach(struct mScriptContext* context, struct mScriptGamepad* pad) {
|
||||
struct mScriptValue* input = mScriptContextGetGlobal(context, "input");
|
||||
if (!input) {
|
||||
|
|
|
@ -131,6 +131,50 @@ M_TEST_DEFINE(activeKeys) {
|
|||
mScriptContextDeinit(&context);
|
||||
}
|
||||
|
||||
M_TEST_DEFINE(clearKeys) {
|
||||
SETUP_LUA;
|
||||
|
||||
TEST_PROGRAM("assert(not input:isKeyActive('a'))");
|
||||
TEST_PROGRAM("assert(not input:isKeyActive('b'))");
|
||||
TEST_PROGRAM("assert(#input:activeKeys() == 0)");
|
||||
|
||||
struct mScriptKeyEvent keyEvent = {
|
||||
.d = { .type = mSCRIPT_EV_TYPE_KEY },
|
||||
.state = mSCRIPT_INPUT_STATE_DOWN,
|
||||
.key = 'a'
|
||||
};
|
||||
mScriptContextFireEvent(&context, &keyEvent.d);
|
||||
// This changes it to STATE_HELD, but increments the down counter
|
||||
mScriptContextFireEvent(&context, &keyEvent.d);
|
||||
keyEvent.state = mSCRIPT_INPUT_STATE_DOWN;
|
||||
keyEvent.key = 'b';
|
||||
mScriptContextFireEvent(&context, &keyEvent.d);
|
||||
|
||||
TEST_PROGRAM("assert(input:isKeyActive('a'))");
|
||||
TEST_PROGRAM("assert(input:isKeyActive('b'))");
|
||||
TEST_PROGRAM("assert(#input:activeKeys() == 2)");
|
||||
|
||||
TEST_PROGRAM(
|
||||
"up = {}\n"
|
||||
"function cb(ev)\n"
|
||||
" assert(ev.type == C.EV_TYPE.KEY)\n"
|
||||
" assert(ev.state == C.INPUT_STATE.UP)\n"
|
||||
" table.insert(up, ev.key)\n"
|
||||
"end\n"
|
||||
"id = callbacks:add('key', cb)\n"
|
||||
);
|
||||
|
||||
mScriptContextClearKeys(&context);
|
||||
|
||||
TEST_PROGRAM("assert(not input:isKeyActive('a'))");
|
||||
TEST_PROGRAM("assert(not input:isKeyActive('b'))");
|
||||
TEST_PROGRAM("assert(#input:activeKeys() == 0)");
|
||||
TEST_PROGRAM("assert(#up == 2)");
|
||||
|
||||
mScriptContextDeinit(&context);
|
||||
}
|
||||
|
||||
|
||||
M_TEST_DEFINE(gamepadExport) {
|
||||
SETUP_LUA;
|
||||
|
||||
|
@ -176,5 +220,6 @@ M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(mScriptInput,
|
|||
cmocka_unit_test(seq),
|
||||
cmocka_unit_test(fireKey),
|
||||
cmocka_unit_test(activeKeys),
|
||||
cmocka_unit_test(clearKeys),
|
||||
cmocka_unit_test(gamepadExport),
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue