Merge branch 'master' into medusa
2
CHANGES
|
@ -88,11 +88,13 @@ Emulation fixes:
|
||||||
- GBA Video: Fix sprites with mid-frame palette changes in GL (fixes mgba.io/i/2476)
|
- GBA Video: Fix sprites with mid-frame palette changes in GL (fixes mgba.io/i/2476)
|
||||||
- GBA Video: Fix OBJ tile wrapping with 2D char mapping (fixes mgba.io/i/2443)
|
- GBA Video: Fix OBJ tile wrapping with 2D char mapping (fixes mgba.io/i/2443)
|
||||||
- GBA Video: Fix horizontal lines in GL when charbase is changed (fixes mgba.io/i/1631)
|
- GBA Video: Fix horizontal lines in GL when charbase is changed (fixes mgba.io/i/1631)
|
||||||
|
- GBA Video: Fix sprite layer priority updating in GL
|
||||||
Other fixes:
|
Other fixes:
|
||||||
- ARM: Disassemble Thumb mov pseudo-instruction properly
|
- ARM: Disassemble Thumb mov pseudo-instruction properly
|
||||||
- Core: Don't attempt to restore rewind diffs past start of rewind
|
- Core: Don't attempt to restore rewind diffs past start of rewind
|
||||||
- Core: Fix the runloop resuming after a game has crashed (fixes mgba.io/i/2451)
|
- Core: Fix the runloop resuming after a game has crashed (fixes mgba.io/i/2451)
|
||||||
- Core: Fix crash if library can't be opened
|
- Core: Fix crash if library can't be opened
|
||||||
|
- Debugger: Fix crash with extremely long CLI strings
|
||||||
- FFmpeg: Fix crash when encoding audio with some containers
|
- FFmpeg: Fix crash when encoding audio with some containers
|
||||||
- FFmpeg: Fix GIF recording (fixes mgba.io/i/2393)
|
- FFmpeg: Fix GIF recording (fixes mgba.io/i/2393)
|
||||||
- GB: Fix temporary saves
|
- GB: Fix temporary saves
|
||||||
|
|
|
@ -98,6 +98,7 @@ CXX_GUARD_START
|
||||||
} \
|
} \
|
||||||
|
|
||||||
DECLARE_VECTOR(StringList, char*);
|
DECLARE_VECTOR(StringList, char*);
|
||||||
|
DECLARE_VECTOR(IntList, int);
|
||||||
|
|
||||||
CXX_GUARD_END
|
CXX_GUARD_END
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ DECL_BITS(mMapCacheSystemInfo, TilesWide, 8, 4);
|
||||||
DECL_BITS(mMapCacheSystemInfo, TilesHigh, 12, 4);
|
DECL_BITS(mMapCacheSystemInfo, TilesHigh, 12, 4);
|
||||||
DECL_BITS(mMapCacheSystemInfo, MacroTileSize, 16, 7);
|
DECL_BITS(mMapCacheSystemInfo, MacroTileSize, 16, 7);
|
||||||
DECL_BITS(mMapCacheSystemInfo, MapAlign, 23, 2);
|
DECL_BITS(mMapCacheSystemInfo, MapAlign, 23, 2);
|
||||||
|
DECL_BITS(mMapCacheSystemInfo, WriteAlign, 25, 2);
|
||||||
|
|
||||||
DECL_BITFIELD(mMapCacheEntryFlags, uint16_t);
|
DECL_BITFIELD(mMapCacheEntryFlags, uint16_t);
|
||||||
DECL_BITS(mMapCacheEntryFlags, PaletteId, 0, 4);
|
DECL_BITS(mMapCacheEntryFlags, PaletteId, 0, 4);
|
||||||
|
|
|
@ -43,7 +43,7 @@ enum Operation {
|
||||||
|
|
||||||
struct Token {
|
struct Token {
|
||||||
enum TokenType {
|
enum TokenType {
|
||||||
TOKEN_ERROR_TYPE,
|
TOKEN_ERROR_TYPE = 0,
|
||||||
TOKEN_UINT_TYPE,
|
TOKEN_UINT_TYPE,
|
||||||
TOKEN_IDENTIFIER_TYPE,
|
TOKEN_IDENTIFIER_TYPE,
|
||||||
TOKEN_OPERATOR_TYPE,
|
TOKEN_OPERATOR_TYPE,
|
||||||
|
@ -60,8 +60,10 @@ struct Token {
|
||||||
|
|
||||||
struct ParseTree {
|
struct ParseTree {
|
||||||
struct Token token;
|
struct Token token;
|
||||||
|
struct ParseTree* p;
|
||||||
struct ParseTree* lhs;
|
struct ParseTree* lhs;
|
||||||
struct ParseTree* rhs;
|
struct ParseTree* rhs;
|
||||||
|
int precedence;
|
||||||
};
|
};
|
||||||
|
|
||||||
size_t lexExpression(struct LexVector* lv, const char* string, size_t length, const char* eol);
|
size_t lexExpression(struct LexVector* lv, const char* string, size_t length, const char* eol);
|
||||||
|
|
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 3.2 KiB |
|
@ -0,0 +1,2 @@
|
||||||
|
<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'>
|
||||||
|
<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="1.5" version="1.1" viewBox="0 0 128 128" xmlns="http://www.w3.org/2000/svg"><g transform="translate(-1.9946)"><path d="m101.49 9.18c0-1.656-1.343-3-3-3h-64.262c-1.656 0-3 1.344-3 3v109.64c0 1.656 1.344 3 3 3h51.262c8.837 0 16-7.164 16-16v-96.64z" fill="#d8d6d1" stroke="#000" stroke-width="1px"/><g transform="matrix(1 0 5.5511e-17 1 0 .34429)"><path d="m31.5 12.156h69.989" fill="none" stroke="#b9b4ad" stroke-width="1px"/></g><path d="M72.2,121.82L101.489,106" fill="none" stroke="#f2ebe2" stroke-width="1px"/><g transform="translate(-.95405)"><path d="M96.408,6.18L96.5,12.5" fill="none" stroke="#b9b4ad" stroke-width="1px"/></g><g transform="translate(-59.954)"><path d="M96.408,6.18L96.5,12.5" fill="none" stroke="#b9b4ad" stroke-width="1px"/></g><path d="m101.49 9.5c0-0.796-0.316-1.559-0.878-2.121-0.563-0.563-1.326-0.879-2.122-0.879h-64.989c-0.796 0-1.559 0.316-2.121 0.879-0.563 0.562-0.879 1.325-0.879 2.121v109c0 0.796 0.316 1.559 0.879 2.121 0.562 0.563 1.325 0.879 2.121 0.879h51.989c8.837 0 16-7.163 16-16v-96z" fill="none" stroke="#000" stroke-width="3px"/><g transform="matrix(.83673 -.3777 .31287 .69311 -23.362 51.852)"><path d="m61.877 104.68c0-0.726-0.488-1.315-1.089-1.315h-6.536c-0.601 0-1.089 0.589-1.089 1.315s0.488 1.315 1.089 1.315h6.536c0.601 0 1.089-0.589 1.089-1.315z" fill="#4e5247" stroke="#000" stroke-width="1.19px"/></g><g transform="matrix(.83673 -.3777 .31287 .69311 -11.362 51.852)"><path d="m61.877 104.68c0-0.726-0.488-1.315-1.089-1.315h-6.536c-0.601 0-1.089 0.589-1.089 1.315s0.488 1.315 1.089 1.315h6.536c0.601 0 1.089-0.589 1.089-1.315z" fill="#4e5247" stroke="#000" stroke-width="1.19px"/></g><circle cx="80.996" cy="87.339" r="3.822" fill="#c11c40" stroke="#000" stroke-width="1px"/><g transform="translate(11.504 -5.7393)"><circle cx="80.996" cy="87.339" r="3.822" fill="#c11c40" stroke="#000" stroke-width="1px"/></g><g transform="translate(-3.7654 1.1875)"><path d="m79.313 108.69 5.505 9.25" fill="none" stroke="#b9b4ad" stroke-width="1px"/></g><g transform="translate(-.2654 -.5125)"><path d="m79.313 108.69 5.505 9.25" fill="none" stroke="#b9b4ad" stroke-width="1px"/></g><g transform="translate(3.2346 -2.2125)"><path d="m79.313 108.69 5.505 9.25" fill="none" stroke="#b9b4ad" stroke-width="1px"/></g><g transform="translate(6.7346 -3.9125)"><path d="m79.313 108.69 5.505 9.25" fill="none" stroke="#b9b4ad" stroke-width="1px"/></g><g transform="translate(10.235 -5.6125)"><path d="m79.313 108.69 5.505 9.25" fill="none" stroke="#b9b4ad" stroke-width="1px"/></g><g transform="translate(13.735 -7.3125)"><path d="m79.313 108.69 5.505 9.25" fill="none" stroke="#b9b4ad" stroke-width="1px"/></g><g transform="translate(0 .40778)"><path d="m96.5 18.203c0-1.104-0.895-2-2-2h-56.964c-1.105 0-2 0.896-2 2v40.778c0 1.105 0.895 2 2 2h49.964c4.971 0 9-4.029 9-9v-33.778z" fill="#848484" stroke="#000" stroke-width="1px"/></g><g transform="matrix(.98813 0 0 .99674 .59124 .25498)"><rect x="47.472" y="21.314" width="37.444" height="34.111" fill="#809a24" stroke="#000" stroke-width="1.01px"/></g><circle cx="40.583" cy="33.426" r="1.389" fill="#ff0025"/><path d="m48.5 82.456h6v5h-6v6h-5v-6h-6v-5h6v-6h5v6z" fill="#4e5247" stroke="#000" stroke-width="1px"/></g></svg>
|
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 5.5 KiB |
|
@ -0,0 +1,2 @@
|
||||||
|
<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'>
|
||||||
|
<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="1.5" version="1.1" viewBox="0 0 128 128" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1.1259)"><path d="m115.98 43.503 1.894-0.666s-0.87-2.15-1.894-3.481-2.356-2.151-4.25-2.867c-1.894-0.717-7.834-0.82-10.496-1.434s-7.117-1.331-8.909-1.536-1.997 1.843-1.997 1.843l25.652 8.141z" fill="#a4a6b4" stroke="#000" stroke-width="1px"/><g transform="matrix(-1 0 0 1 128 0)"><path d="m115.98 43.503 1.894-0.666s-0.87-2.15-1.894-3.481-2.356-2.151-4.25-2.867c-1.894-0.717-7.834-0.82-10.496-1.434s-7.117-1.331-8.909-1.536-1.997 1.843-1.997 1.843l25.652 8.141z" fill="#a4a6b4" stroke="#000" stroke-width="1px"/></g><g transform="translate(1.55)"><path d="m62.45 97.95c9.766 0 23.582-1.214 29.8-3.2 1.966-0.628 4.816-2.128 6.8-2.6 4.2-1 8.8-2.6 13-4 3.78-1.26 5.739-4.265 6.4-7.2 1.6-7.1-1.6-32.6-2.2-34.9s-1.2-5.1-4.2-5.7-11.4-2.6-16.4-5.2-9.5-2.5-9.5-2.5-39.5-0.333-47.4 0c0 0-4.5-0.1-9.5 2.5s-13.4 4.6-16.4 5.2-3.6 3.4-4.2 5.7-3.8 27.8-2.2 34.9c0.661 2.935 2.62 5.94 6.4 7.2 4.2 1.4 8.8 3 13 4 1.984 0.472 4.834 1.972 6.8 2.6 6.218 1.986 20.034 3.2 29.8 3.2" fill="#aa86d5" stroke="#000" stroke-width="3px"/></g><g transform="translate(.1024 -.0512)"><circle cx="100.67" cy="43.964" r=".947" fill="#a0ff2a"/></g><path d="m64 39.462c-9.152 0-23.024 1.18-25.584 1.82s-2.687 1.92-2.944 3.264c-1.152 6.016-2.713 30.078-2.048 37.608 0.221 2.507 1.28 3.935 4.16 5.151 3.43 1.448 13.536 3.52 26.416 3.52s22.986-2.072 26.416-3.52c2.88-1.216 3.939-2.644 4.16-5.151 0.665-7.53-0.896-31.592-2.048-37.608-0.257-1.344-0.384-2.624-2.944-3.264s-16.432-1.82-25.584-1.82"/><g transform="matrix(1.0064 0 0 .98449 -.23513 1.695)"><rect x="38.984" y="44.803" width="49.68" height="33.52" fill="#a4a6b4" stroke="#000" stroke-width="1px"/></g><g transform="translate(.48 .30537)"><circle cx="100.79" cy="61.303" r="3.84" fill="#a4a6b4" stroke="#000" stroke-width="1px"/></g><g transform="translate(10.2 -3.5346)"><circle cx="100.79" cy="61.303" r="3.84" fill="#a4a6b4" stroke="#000" stroke-width="1px"/></g><g transform="matrix(.97364 .22811 -.22811 .97364 17.954 -4.6988)"><path d="m29.304 77.118h-8.619c-0.994 0-1.8-0.806-1.8-1.8 0-0.993 0.806-1.8 1.8-1.8h8.619c0.993 0 1.8 0.807 1.8 1.8 0 0.994-0.807 1.8-1.8 1.8z" fill="none" stroke="#986cc4" stroke-width="1px"/></g><g transform="translate(.24 1.7764e-15)"><circle cx="29.064" cy="75.318" r="1.8" fill="#a4a6b4" stroke="#000" stroke-width="1px"/></g><g transform="translate(0 6.4648)"><g transform="matrix(.97364 .22811 -.22811 .97364 17.954 -4.6988)"><path d="m29.304 77.118h-8.619c-0.994 0-1.8-0.806-1.8-1.8 0-0.993 0.806-1.8 1.8-1.8h8.619c0.993 0 1.8 0.807 1.8 1.8 0 0.994-0.807 1.8-1.8 1.8z" fill="none" stroke="#986cc4" stroke-width="1px"/></g><g transform="translate(.24 1.7764e-15)"><circle cx="29.064" cy="75.318" r="1.8" fill="#a4a6b4" stroke="#000" stroke-width="1px"/></g></g><g transform="matrix(1.0302 0 0 1.0302 -.40806 -2.0201)"><path d="m24.051 57.052h4.98v4.6h-4.98v4.98h-4.6v-4.98h-4.98v-4.6h4.98v-4.98h4.6v4.98z" fill="#a4a6b4" stroke="#000" stroke-width=".97px"/></g><path d="m97.413 74.335 11.879-2.783" fill="none" stroke="#986cc4" stroke-width="1px"/><g transform="translate(0 2.3565)"><path d="m97.413 74.335 11.879-2.783" fill="none" stroke="#986cc4" stroke-width="1px"/></g><g transform="translate(0 4.7565)"><path d="m97.413 74.335 11.879-2.783" fill="none" stroke="#986cc4" stroke-width="1px"/></g><g transform="translate(0 7.1565)"><path d="m97.413 74.335 11.879-2.783" fill="none" stroke="#986cc4" stroke-width="1px"/></g><g transform="translate(0 9.4565)"><path d="m97.413 74.335 11.879-2.783" fill="none" stroke="#986cc4" stroke-width="1px"/></g></g></svg>
|
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 10 KiB |
|
@ -189,14 +189,12 @@ static struct ARMDebugBreakpoint* _lookupBreakpoint(struct ARMDebugBreakpointLis
|
||||||
static void _destroyBreakpoint(struct ARMDebugBreakpoint* breakpoint) {
|
static void _destroyBreakpoint(struct ARMDebugBreakpoint* breakpoint) {
|
||||||
if (breakpoint->d.condition) {
|
if (breakpoint->d.condition) {
|
||||||
parseFree(breakpoint->d.condition);
|
parseFree(breakpoint->d.condition);
|
||||||
free(breakpoint->d.condition);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _destroyWatchpoint(struct mWatchpoint* watchpoint) {
|
static void _destroyWatchpoint(struct mWatchpoint* watchpoint) {
|
||||||
if (watchpoint->condition) {
|
if (watchpoint->condition) {
|
||||||
parseFree(watchpoint->condition);
|
parseFree(watchpoint->condition);
|
||||||
free(watchpoint->condition);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -70,11 +70,20 @@ void mMapCacheDeinit(struct mMapCache* cache) {
|
||||||
|
|
||||||
void mMapCacheWriteVRAM(struct mMapCache* cache, uint32_t address) {
|
void mMapCacheWriteVRAM(struct mMapCache* cache, uint32_t address) {
|
||||||
if (address >= cache->mapStart && address < cache->mapStart + cache->mapSize) {
|
if (address >= cache->mapStart && address < cache->mapStart + cache->mapSize) {
|
||||||
|
uint32_t align = 1 << (mMapCacheSystemInfoGetWriteAlign(cache->sysConfig) - mMapCacheSystemInfoGetMapAlign(cache->sysConfig));
|
||||||
address -= cache->mapStart;
|
address -= cache->mapStart;
|
||||||
struct mMapCacheEntry* status = &cache->status[address >> mMapCacheSystemInfoGetMapAlign(cache->sysConfig)];
|
address >>= mMapCacheSystemInfoGetMapAlign(cache->sysConfig);
|
||||||
++status->vramVersion;
|
|
||||||
status->flags = mMapCacheEntryFlagsClearVramClean(status->flags);
|
uint32_t i;
|
||||||
status->tileStatus[mMapCacheEntryFlagsGetPaletteId(status->flags)].vramClean = 0;
|
for (i = 0; i < align; ++i) {
|
||||||
|
if (address + i >= (cache->mapSize >> mMapCacheSystemInfoGetMapAlign(cache->sysConfig))) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
struct mMapCacheEntry* status = &cache->status[address + i];
|
||||||
|
++status->vramVersion;
|
||||||
|
status->flags = mMapCacheEntryFlagsClearVramClean(status->flags);
|
||||||
|
status->tileStatus[mMapCacheEntryFlagsGetPaletteId(status->flags)].vramClean = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -226,11 +226,9 @@ static bool _parseExpression(struct mDebugger* debugger, struct CLIDebugVector*
|
||||||
}
|
}
|
||||||
if (!mDebuggerEvaluateParseTree(debugger, tree, intValue, segmentValue)) {
|
if (!mDebuggerEvaluateParseTree(debugger, tree, intValue, segmentValue)) {
|
||||||
parseFree(tree);
|
parseFree(tree);
|
||||||
free(tree);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
parseFree(tree);
|
parseFree(tree);
|
||||||
free(tree);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -599,7 +597,6 @@ static struct ParseTree* _parseTree(const char** string) {
|
||||||
if (error) {
|
if (error) {
|
||||||
if (tree) {
|
if (tree) {
|
||||||
parseFree(tree);
|
parseFree(tree);
|
||||||
free(tree);
|
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
|
|
||||||
DEFINE_VECTOR(LexVector, struct Token);
|
DEFINE_VECTOR(LexVector, struct Token);
|
||||||
|
|
||||||
|
DEFINE_VECTOR(IntList, int32_t);
|
||||||
|
|
||||||
enum LexState {
|
enum LexState {
|
||||||
LEX_ERROR = -1,
|
LEX_ERROR = -1,
|
||||||
LEX_ROOT = 0,
|
LEX_ROOT = 0,
|
||||||
|
@ -493,16 +495,21 @@ static const int _operatorPrecedence[] = {
|
||||||
[OP_DEREFERENCE] = 2,
|
[OP_DEREFERENCE] = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct ParseTree* _parseTreeCreate() {
|
static struct ParseTree* _parseTreeCreate(void) {
|
||||||
struct ParseTree* tree = malloc(sizeof(struct ParseTree));
|
struct ParseTree* tree = malloc(sizeof(struct ParseTree));
|
||||||
tree->token.type = TOKEN_ERROR_TYPE;
|
tree->token.type = TOKEN_ERROR_TYPE;
|
||||||
tree->rhs = 0;
|
tree->p = NULL;
|
||||||
tree->lhs = 0;
|
tree->rhs = NULL;
|
||||||
|
tree->lhs = NULL;
|
||||||
|
tree->precedence = INT_MAX;
|
||||||
return tree;
|
return tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t _parseExpression(struct ParseTree* tree, struct LexVector* lv, size_t i, int precedence, int* openParens) {
|
static size_t _parseExpression(struct ParseTree* tree, struct LexVector* lv, int* openParens) {
|
||||||
struct ParseTree* newTree = 0;
|
struct ParseTree* newTree = NULL;
|
||||||
|
bool pop = false;
|
||||||
|
int precedence = INT_MAX;
|
||||||
|
size_t i = 0;
|
||||||
while (i < LexVectorSize(lv)) {
|
while (i < LexVectorSize(lv)) {
|
||||||
struct Token* token = LexVectorGetPointer(lv, i);
|
struct Token* token = LexVectorGetPointer(lv, i);
|
||||||
int newPrecedence;
|
int newPrecedence;
|
||||||
|
@ -517,27 +524,36 @@ static size_t _parseExpression(struct ParseTree* tree, struct LexVector* lv, siz
|
||||||
++i;
|
++i;
|
||||||
} else {
|
} else {
|
||||||
tree->token.type = TOKEN_ERROR_TYPE;
|
tree->token.type = TOKEN_ERROR_TYPE;
|
||||||
return i + 1;
|
++i;
|
||||||
|
pop = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TOKEN_SEGMENT_TYPE:
|
case TOKEN_SEGMENT_TYPE:
|
||||||
tree->lhs = _parseTreeCreate();
|
tree->lhs = _parseTreeCreate();
|
||||||
tree->lhs->token.type = TOKEN_UINT_TYPE;
|
tree->lhs->token.type = TOKEN_UINT_TYPE;
|
||||||
tree->lhs->token.uintValue = token->uintValue;
|
tree->lhs->token.uintValue = token->uintValue;
|
||||||
|
tree->lhs->p = tree;
|
||||||
|
tree->lhs->precedence = precedence;
|
||||||
tree->rhs = _parseTreeCreate();
|
tree->rhs = _parseTreeCreate();
|
||||||
|
tree->rhs->p = tree;
|
||||||
|
tree->rhs->precedence = precedence;
|
||||||
tree->token.type = TOKEN_SEGMENT_TYPE;
|
tree->token.type = TOKEN_SEGMENT_TYPE;
|
||||||
i = _parseExpression(tree->rhs, lv, i + 1, precedence, openParens);
|
tree = tree->rhs;
|
||||||
|
++i;
|
||||||
break;
|
break;
|
||||||
case TOKEN_OPEN_PAREN_TYPE:
|
case TOKEN_OPEN_PAREN_TYPE:
|
||||||
++*openParens;
|
++*openParens;
|
||||||
i = _parseExpression(tree, lv, i + 1, INT_MAX, openParens);
|
precedence = INT_MAX;
|
||||||
|
++i;
|
||||||
break;
|
break;
|
||||||
case TOKEN_CLOSE_PAREN_TYPE:
|
case TOKEN_CLOSE_PAREN_TYPE:
|
||||||
if (*openParens <= 0) {
|
if (*openParens <= 0) {
|
||||||
tree->token.type = TOKEN_ERROR_TYPE;
|
tree->token.type = TOKEN_ERROR_TYPE;
|
||||||
}
|
}
|
||||||
--*openParens;
|
--*openParens;
|
||||||
return i + 1;
|
++i;
|
||||||
|
pop = true;
|
||||||
|
break;
|
||||||
case TOKEN_OPERATOR_TYPE:
|
case TOKEN_OPERATOR_TYPE:
|
||||||
if (tree->token.type == TOKEN_ERROR_TYPE) {
|
if (tree->token.type == TOKEN_ERROR_TYPE) {
|
||||||
switch (token->operatorValue) {
|
switch (token->operatorValue) {
|
||||||
|
@ -557,21 +573,44 @@ static size_t _parseExpression(struct ParseTree* tree, struct LexVector* lv, siz
|
||||||
newPrecedence = _operatorPrecedence[token->operatorValue];
|
newPrecedence = _operatorPrecedence[token->operatorValue];
|
||||||
if (newPrecedence < precedence) {
|
if (newPrecedence < precedence) {
|
||||||
newTree = _parseTreeCreate();
|
newTree = _parseTreeCreate();
|
||||||
*newTree = *tree;
|
memcpy(newTree, tree, sizeof(*tree));
|
||||||
|
if (newTree->lhs) {
|
||||||
|
newTree->lhs->p = newTree;
|
||||||
|
}
|
||||||
|
if (newTree->rhs) {
|
||||||
|
newTree->rhs->p = newTree;
|
||||||
|
}
|
||||||
|
newTree->p = tree;
|
||||||
tree->lhs = newTree;
|
tree->lhs = newTree;
|
||||||
tree->rhs = _parseTreeCreate();
|
tree->rhs = _parseTreeCreate();
|
||||||
|
tree->rhs->p = tree;
|
||||||
|
tree->rhs->precedence = newPrecedence;
|
||||||
|
precedence = newPrecedence;
|
||||||
tree->token = *token;
|
tree->token = *token;
|
||||||
i = _parseExpression(tree->rhs, lv, i + 1, newPrecedence, openParens);
|
tree = tree->rhs;
|
||||||
if (tree->token.type == TOKEN_ERROR_TYPE) {
|
++i;
|
||||||
tree->token.type = TOKEN_ERROR_TYPE;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return i;
|
pop = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TOKEN_ERROR_TYPE:
|
case TOKEN_ERROR_TYPE:
|
||||||
tree->token.type = TOKEN_ERROR_TYPE;
|
tree->token.type = TOKEN_ERROR_TYPE;
|
||||||
return i + 1;
|
++i;
|
||||||
|
pop = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pop) {
|
||||||
|
if (tree->token.type == TOKEN_ERROR_TYPE && tree->p) {
|
||||||
|
tree->p->token.type = TOKEN_ERROR_TYPE;
|
||||||
|
}
|
||||||
|
tree = tree->p;
|
||||||
|
pop = false;
|
||||||
|
if (!tree) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
precedence = tree->precedence;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -584,11 +623,13 @@ void parseLexedExpression(struct ParseTree* tree, struct LexVector* lv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
tree->token.type = TOKEN_ERROR_TYPE;
|
tree->token.type = TOKEN_ERROR_TYPE;
|
||||||
tree->lhs = 0;
|
tree->lhs = NULL;
|
||||||
tree->rhs = 0;
|
tree->rhs = NULL;
|
||||||
|
tree->p = NULL;
|
||||||
|
tree->precedence = INT_MAX;
|
||||||
|
|
||||||
int openParens = 0;
|
int openParens = 0;
|
||||||
_parseExpression(tree, lv, 0, INT_MAX, &openParens);
|
_parseExpression(tree, lv, &openParens);
|
||||||
if (openParens) {
|
if (openParens) {
|
||||||
if (tree->token.type == TOKEN_IDENTIFIER_TYPE) {
|
if (tree->token.type == TOKEN_IDENTIFIER_TYPE) {
|
||||||
free(tree->token.identifierValue);
|
free(tree->token.identifierValue);
|
||||||
|
@ -607,23 +648,40 @@ void lexFree(struct LexVector* lv) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void parseFree(struct ParseTree* tree) {
|
static void _freeTree(struct ParseTree* tree) {
|
||||||
if (!tree) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tree->lhs) {
|
|
||||||
parseFree(tree->lhs);
|
|
||||||
free(tree->lhs);
|
|
||||||
}
|
|
||||||
if (tree->rhs) {
|
|
||||||
parseFree(tree->rhs);
|
|
||||||
free(tree->rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tree->token.type == TOKEN_IDENTIFIER_TYPE) {
|
if (tree->token.type == TOKEN_IDENTIFIER_TYPE) {
|
||||||
free(tree->token.identifierValue);
|
free(tree->token.identifierValue);
|
||||||
}
|
}
|
||||||
|
free(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
void parseFree(struct ParseTree* tree) {
|
||||||
|
while (tree) {
|
||||||
|
if (tree->lhs) {
|
||||||
|
tree = tree->lhs;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (tree->rhs) {
|
||||||
|
tree = tree->rhs;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (tree->p) {
|
||||||
|
if (tree->p->lhs == tree) {
|
||||||
|
tree = tree->p;
|
||||||
|
_freeTree(tree->lhs);
|
||||||
|
tree->lhs = NULL;
|
||||||
|
} else if (tree->p->rhs == tree) {
|
||||||
|
tree = tree->p;
|
||||||
|
_freeTree(tree->rhs);
|
||||||
|
tree->rhs = NULL;
|
||||||
|
} else {
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_freeTree(tree);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _performOperation(struct mDebugger* debugger, enum Operation operation, int32_t current, int32_t next, int32_t* value, int* segment) {
|
static bool _performOperation(struct mDebugger* debugger, enum Operation operation, int32_t current, int32_t next, int32_t* value, int* segment) {
|
||||||
|
@ -721,56 +779,124 @@ bool mDebuggerEvaluateParseTree(struct mDebugger* debugger, struct ParseTree* tr
|
||||||
if (!value) {
|
if (!value) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int32_t lhs, rhs;
|
struct IntList stack;
|
||||||
switch (tree->token.type) {
|
int nextBranch;
|
||||||
case TOKEN_UINT_TYPE:
|
bool ok = true;
|
||||||
if (segment) {
|
int32_t tmpVal, tmpSegment;
|
||||||
*segment = -1;
|
|
||||||
}
|
IntListInit(&stack, 0);
|
||||||
*value = tree->token.uintValue;
|
while (ok) {
|
||||||
return true;
|
switch (tree->token.type) {
|
||||||
case TOKEN_SEGMENT_TYPE:
|
case TOKEN_UINT_TYPE:
|
||||||
if (!mDebuggerEvaluateParseTree(debugger, tree->rhs, value, segment)) {
|
nextBranch = 2;
|
||||||
return false;
|
tmpSegment = -1;
|
||||||
}
|
tmpVal = tree->token.uintValue;
|
||||||
return mDebuggerEvaluateParseTree(debugger, tree->lhs, segment, NULL);
|
break;
|
||||||
case TOKEN_OPERATOR_TYPE:
|
case TOKEN_SEGMENT_TYPE:
|
||||||
switch (tree->token.operatorValue) {
|
nextBranch = 0;
|
||||||
case OP_ASSIGN:
|
break;
|
||||||
case OP_ADD:
|
case TOKEN_OPERATOR_TYPE:
|
||||||
case OP_SUBTRACT:
|
switch (tree->token.operatorValue) {
|
||||||
case OP_MULTIPLY:
|
case OP_ASSIGN:
|
||||||
case OP_DIVIDE:
|
case OP_ADD:
|
||||||
case OP_MODULO:
|
case OP_SUBTRACT:
|
||||||
case OP_AND:
|
case OP_MULTIPLY:
|
||||||
case OP_OR:
|
case OP_DIVIDE:
|
||||||
case OP_XOR:
|
case OP_MODULO:
|
||||||
case OP_LESS:
|
case OP_AND:
|
||||||
case OP_GREATER:
|
case OP_OR:
|
||||||
case OP_EQUAL:
|
case OP_XOR:
|
||||||
case OP_NOT_EQUAL:
|
case OP_LESS:
|
||||||
case OP_LOGICAL_AND:
|
case OP_GREATER:
|
||||||
case OP_LOGICAL_OR:
|
case OP_EQUAL:
|
||||||
case OP_LE:
|
case OP_NOT_EQUAL:
|
||||||
case OP_GE:
|
case OP_LOGICAL_AND:
|
||||||
case OP_SHIFT_L:
|
case OP_LOGICAL_OR:
|
||||||
case OP_SHIFT_R:
|
case OP_LE:
|
||||||
if (!mDebuggerEvaluateParseTree(debugger, tree->lhs, &lhs, segment)) {
|
case OP_GE:
|
||||||
return false;
|
case OP_SHIFT_L:
|
||||||
}
|
case OP_SHIFT_R:
|
||||||
// Fall through
|
nextBranch = 0;
|
||||||
default:
|
break;
|
||||||
if (!mDebuggerEvaluateParseTree(debugger, tree->rhs, &rhs, segment)) {
|
default:
|
||||||
return false;
|
nextBranch = 1;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case TOKEN_IDENTIFIER_TYPE:
|
||||||
|
if (!mDebuggerLookupIdentifier(debugger, tree->token.identifierValue, &tmpVal, &tmpSegment)) {
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
|
nextBranch = 2;
|
||||||
|
break;
|
||||||
|
case TOKEN_ERROR_TYPE:
|
||||||
|
default:
|
||||||
|
ok = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!ok) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool gotTree = false;
|
||||||
|
while (!gotTree && tree) {
|
||||||
|
int32_t lhs, rhs;
|
||||||
|
|
||||||
|
switch (nextBranch) {
|
||||||
|
case 0:
|
||||||
|
*IntListAppend(&stack) = tmpVal;
|
||||||
|
*IntListAppend(&stack) = tmpSegment;
|
||||||
|
*IntListAppend(&stack) = nextBranch;
|
||||||
|
tree = tree->lhs;
|
||||||
|
gotTree = true;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
*IntListAppend(&stack) = tmpVal;
|
||||||
|
*IntListAppend(&stack) = tmpSegment;
|
||||||
|
*IntListAppend(&stack) = nextBranch;
|
||||||
|
tree = tree->rhs;
|
||||||
|
gotTree = true;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if (!IntListSize(&stack)) {
|
||||||
|
tree = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
nextBranch = *IntListGetPointer(&stack, IntListSize(&stack) - 1);
|
||||||
|
IntListResize(&stack, -1);
|
||||||
|
tree = tree->p;
|
||||||
|
if (nextBranch == 0) {
|
||||||
|
++nextBranch;
|
||||||
|
} else if (tree) {
|
||||||
|
nextBranch = 2;
|
||||||
|
switch (tree->token.type) {
|
||||||
|
case TOKEN_OPERATOR_TYPE:
|
||||||
|
rhs = tmpVal;
|
||||||
|
lhs = *IntListGetPointer(&stack, IntListSize(&stack) - 2);
|
||||||
|
tmpSegment = *IntListGetPointer(&stack, IntListSize(&stack) - 1);
|
||||||
|
ok = _performOperation(debugger, tree->token.operatorValue, lhs, rhs, &tmpVal, &tmpSegment);
|
||||||
|
break;
|
||||||
|
case TOKEN_SEGMENT_TYPE:
|
||||||
|
tmpSegment = *IntListGetPointer(&stack, IntListSize(&stack) - 2);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IntListResize(&stack, -2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!tree) {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return _performOperation(debugger, tree->token.operatorValue, lhs, rhs, value, segment);
|
|
||||||
case TOKEN_IDENTIFIER_TYPE:
|
|
||||||
return mDebuggerLookupIdentifier(debugger, tree->token.identifierValue, value, segment);
|
|
||||||
case TOKEN_ERROR_TYPE:
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return false;
|
IntListDeinit(&stack);
|
||||||
|
if (ok) {
|
||||||
|
*value = tmpVal;
|
||||||
|
if (segment) {
|
||||||
|
*segment = tmpSegment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
struct LPTest {
|
struct LPTest {
|
||||||
struct LexVector lv;
|
struct LexVector lv;
|
||||||
struct ParseTree tree;
|
struct ParseTree* tree;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define PARSE(STR) \
|
#define PARSE(STR) \
|
||||||
|
@ -18,7 +18,8 @@ struct LPTest {
|
||||||
LexVectorClear(&lp->lv); \
|
LexVectorClear(&lp->lv); \
|
||||||
size_t adjusted = lexExpression(&lp->lv, STR, strlen(STR), ""); \
|
size_t adjusted = lexExpression(&lp->lv, STR, strlen(STR), ""); \
|
||||||
assert_false(adjusted > strlen(STR)); \
|
assert_false(adjusted > strlen(STR)); \
|
||||||
struct ParseTree* tree = &lp->tree; \
|
lp->tree = malloc(sizeof(*lp->tree)); \
|
||||||
|
struct ParseTree* tree = lp->tree; \
|
||||||
parseLexedExpression(tree, &lp->lv)
|
parseLexedExpression(tree, &lp->lv)
|
||||||
|
|
||||||
static int parseSetup(void** state) {
|
static int parseSetup(void** state) {
|
||||||
|
@ -30,7 +31,7 @@ static int parseSetup(void** state) {
|
||||||
|
|
||||||
static int parseTeardown(void** state) {
|
static int parseTeardown(void** state) {
|
||||||
struct LPTest* lp = *state;
|
struct LPTest* lp = *state;
|
||||||
parseFree(&lp->tree);
|
parseFree(lp->tree);
|
||||||
lexFree(&lp->lv);
|
lexFree(&lp->lv);
|
||||||
LexVectorDeinit(&lp->lv);
|
LexVectorDeinit(&lp->lv);
|
||||||
free(lp);
|
free(lp);
|
||||||
|
|
|
@ -119,6 +119,7 @@ void GBVideoCacheWriteVideoRegister(struct mCacheSet* cache, uint16_t address, u
|
||||||
sysconfig = mMapCacheSystemInfoSetMacroTileSize(sysconfig, 5);
|
sysconfig = mMapCacheSystemInfoSetMacroTileSize(sysconfig, 5);
|
||||||
sysconfig = mMapCacheSystemInfoSetPaletteBPP(sysconfig, 1);
|
sysconfig = mMapCacheSystemInfoSetPaletteBPP(sysconfig, 1);
|
||||||
sysconfig = mMapCacheSystemInfoSetMapAlign(sysconfig, 0);
|
sysconfig = mMapCacheSystemInfoSetMapAlign(sysconfig, 0);
|
||||||
|
sysconfig = mMapCacheSystemInfoSetWriteAlign(sysconfig, 0);
|
||||||
sysconfig = mMapCacheSystemInfoSetTilesHigh(sysconfig, 5);
|
sysconfig = mMapCacheSystemInfoSetTilesHigh(sysconfig, 5);
|
||||||
sysconfig = mMapCacheSystemInfoSetTilesWide(sysconfig, 5);
|
sysconfig = mMapCacheSystemInfoSetTilesWide(sysconfig, 5);
|
||||||
mMapCacheConfigureSystem(map, sysconfig);
|
mMapCacheConfigureSystem(map, sysconfig);
|
||||||
|
|
|
@ -160,7 +160,7 @@ static void GBAVideoCacheWriteBGCNT(struct mCacheSet* cache, size_t bg, uint16_t
|
||||||
int size = GBARegisterBGCNTGetSize(value);
|
int size = GBARegisterBGCNTGetSize(value);
|
||||||
int tilesWide = 0;
|
int tilesWide = 0;
|
||||||
int tilesHigh = 0;
|
int tilesHigh = 0;
|
||||||
mMapCacheSystemInfo sysconfig = 0;
|
mMapCacheSystemInfo sysconfig = mMapCacheSystemInfoSetWriteAlign(0, 1);
|
||||||
if (map->mapParser == mapParser0) {
|
if (map->mapParser == mapParser0) {
|
||||||
map->tileCache = mTileCacheSetGetPointer(&cache->tiles, p);
|
map->tileCache = mTileCacheSetGetPointer(&cache->tiles, p);
|
||||||
sysconfig = mMapCacheSystemInfoSetPaletteBPP(sysconfig, 2 + p);
|
sysconfig = mMapCacheSystemInfoSetPaletteBPP(sysconfig, 2 + p);
|
||||||
|
|
|
@ -1808,9 +1808,9 @@ void GBAVideoGLRendererDrawSprite(struct GBAVideoGLRenderer* renderer, struct GB
|
||||||
glUniformMatrix2fv(uniforms[GBA_GL_OBJ_TRANSFORM], 1, GL_FALSE, (GLfloat[]) { flipX, 0, 0, flipY });
|
glUniformMatrix2fv(uniforms[GBA_GL_OBJ_TRANSFORM], 1, GL_FALSE, (GLfloat[]) { flipX, 0, 0, flipY });
|
||||||
}
|
}
|
||||||
glUniform4i(uniforms[GBA_GL_OBJ_DIMS], width, height, totalWidth, totalHeight);
|
glUniform4i(uniforms[GBA_GL_OBJ_DIMS], width, height, totalWidth, totalHeight);
|
||||||
glDisable(GL_STENCIL_TEST);
|
|
||||||
if (GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_OBJWIN) {
|
if (GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_OBJWIN) {
|
||||||
// OBJWIN writes do not affect pixel priority
|
// OBJWIN writes do not affect pixel priority
|
||||||
|
glDisable(GL_STENCIL_TEST);
|
||||||
glDisable(GL_DEPTH_TEST);
|
glDisable(GL_DEPTH_TEST);
|
||||||
glDepthMask(GL_FALSE);
|
glDepthMask(GL_FALSE);
|
||||||
glStencilMask(0);
|
glStencilMask(0);
|
||||||
|
@ -1818,6 +1818,7 @@ void GBAVideoGLRendererDrawSprite(struct GBAVideoGLRenderer* renderer, struct GB
|
||||||
glUniform3i(uniforms[GBA_GL_OBJ_OBJWIN], window, renderer->bldb, renderer->bldy);
|
glUniform3i(uniforms[GBA_GL_OBJ_OBJWIN], window, renderer->bldb, renderer->bldy);
|
||||||
glDrawBuffers(3, (GLenum[]) { GL_NONE, GL_NONE, GL_COLOR_ATTACHMENT2 });
|
glDrawBuffers(3, (GLenum[]) { GL_NONE, GL_NONE, GL_COLOR_ATTACHMENT2 });
|
||||||
} else {
|
} else {
|
||||||
|
glEnable(GL_STENCIL_TEST);
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
glDepthMask(GL_TRUE);
|
glDepthMask(GL_TRUE);
|
||||||
glStencilMask(1);
|
glStencilMask(1);
|
||||||
|
@ -1842,7 +1843,6 @@ void GBAVideoGLRendererDrawSprite(struct GBAVideoGLRenderer* renderer, struct GB
|
||||||
// Update the pixel priority for already-written pixels
|
// Update the pixel priority for already-written pixels
|
||||||
shader = &renderer->objShader[2];
|
shader = &renderer->objShader[2];
|
||||||
uniforms = shader->uniforms;
|
uniforms = shader->uniforms;
|
||||||
glEnable(GL_STENCIL_TEST);
|
|
||||||
glStencilFunc(GL_EQUAL, 1, 1);
|
glStencilFunc(GL_EQUAL, 1, 1);
|
||||||
glUseProgram(shader->program);
|
glUseProgram(shader->program);
|
||||||
glDrawBuffers(2, (GLenum[]) { GL_NONE, GL_COLOR_ATTACHMENT1 });
|
glDrawBuffers(2, (GLenum[]) { GL_NONE, GL_COLOR_ATTACHMENT1 });
|
||||||
|
|
|
@ -28,14 +28,12 @@ static struct mBreakpoint* _lookupBreakpoint(struct mBreakpointList* breakpoints
|
||||||
static void _destroyBreakpoint(struct mBreakpoint* breakpoint) {
|
static void _destroyBreakpoint(struct mBreakpoint* breakpoint) {
|
||||||
if (breakpoint->condition) {
|
if (breakpoint->condition) {
|
||||||
parseFree(breakpoint->condition);
|
parseFree(breakpoint->condition);
|
||||||
free(breakpoint->condition);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _destroyWatchpoint(struct mWatchpoint* watchpoint) {
|
static void _destroyWatchpoint(struct mWatchpoint* watchpoint) {
|
||||||
if (watchpoint->condition) {
|
if (watchpoint->condition) {
|
||||||
parseFree(watchpoint->condition);
|
parseFree(watchpoint->condition);
|
||||||
free(watchpoint->condition);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|