From 19f705076aec2c26bcc52a4e406f6886f0fc26f0 Mon Sep 17 00:00:00 2001 From: fincs Date: Mon, 15 Dec 2014 22:59:06 +0100 Subject: [PATCH] Add support for BREAKC/CALLC/IFC/JMPC --- Manual.md | 7 ++- source/picasso_assembler.cpp | 106 +++++++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+), 2 deletions(-) diff --git a/Manual.md b/Manual.md index 3021339..f00e76b 100644 --- a/Manual.md +++ b/Manual.md @@ -201,7 +201,7 @@ Syntax | Description - `bReg`: Represents a boolean uniform source operand. - `procName`: Represents the name of a procedure. - `labelName`: Represents the name of a label. -- `opx` and `opy`: They represent a conditional operator that is applied to the source registers and whose result is stored in the appropriate flag (cmp.x and cmp.y respectively). Supported values include: +- `opx` and `opy`: They represent a conditional operator that is applied to the source registers and whose result is stored in the appropriate flag (`cmp.x` and `cmp.y` respectively). Supported values include: - `eq`: Equal - `ne`: Not equal - `lt`: Less than @@ -209,4 +209,7 @@ Syntax | Description - `gt`: Greater than - `ge`: Greater or equal than - `6` and `7`: currently unknown, supposedly the result they yield is always true. -- `condExp`: Represents a conditional expression. Currently this is not implemented. +- `condExp`: Represents a conditional expression, which uses the conditional flags `cmp.x` and `cmp.y` set by the CMP instruction. These flags may be negated using the `!` symbol, e.g. `!cmp.x`. The conditional expression can take any of the following forms: + - `flag1`: It tests a single flag. + - `flag1 && flag2`: It performs AND between the two flags. Optionally, a single `&` may be specified. + - `flag1 || flag2`: It performs OR between the two flags. Optionally, a single `|` may be specified. diff --git a/source/picasso_assembler.cpp b/source/picasso_assembler.cpp index 081a56d..1d1c8cc 100644 --- a/source/picasso_assembler.cpp +++ b/source/picasso_assembler.cpp @@ -590,6 +590,53 @@ static int parseReg(char* pos, int& outReg, int& outSw, int* idxType = NULL) return 0; } +static int parseCondExpOp(char* str, u32& outFlags, int& which) +{ + int negation = 0; + for (; *str == '!'; str++) negation ^= 1; + if (stricmp(str, "cmp.x")==0) + { + which = 1; + outFlags ^= negation<<25; + return 0; + } + if (stricmp(str, "cmp.y")==0) + { + which = 0; + outFlags ^= negation<<24; + return 0; + } + return throwError("invalid condition register: %s\n", str); +} + +static int parseCondExp(char* str, u32& outFlags) +{ + outFlags = BIT(24) | BIT(25); + size_t len = strlen(str); + size_t pos = strcspn(str, "&|"); + int op2 = -1; + if (pos < len) + { + char* str2 = str + pos; + int type = *str2; + *str2++ = 0; + if (*str2 == type) + str2++; + str = trim_whitespace(str); + str2 = trim_whitespace(str2); + if (type == '&') + outFlags |= 1<<22; + safe_call(parseCondExpOp(str2, outFlags, op2)); + } + int op1 = -1; + safe_call(parseCondExpOp(str, outFlags, op1)); + if (op1 == op2) + return throwError("condition register checked twice\n"); + if (op2 < 0) + outFlags |= (op1+2)<<22; + return 0; +} + DEF_COMMAND(format0) { ENSURE_NO_MORE_ARGS(); @@ -776,6 +823,64 @@ DEF_COMMAND(formatfor) DEF_COMMAND(format2) { + NEXT_ARG(condExp); + + u32 instruction = 0; + safe_call(parseCondExp(condExp, instruction)); + + switch (opcode) + { + case MAESTRO_BREAKC: + { + ENSURE_NO_MORE_ARGS(); + +#ifdef DEBUG + printf("%s:%02X %s\n", cmdName, opcode, condExp); +#endif + break; + } + + case MAESTRO_CALLC: + case MAESTRO_JMPC: + { + NEXT_ARG(targetName); + ENSURE_NO_MORE_ARGS(); + + ARG_TARGET(targetName); + + Relocation r; + r.instPos = BUF.size(); + r.target = targetName; + r.isProc = opcode==MAESTRO_CALLC; + g_relocs.push_back(r); + +#ifdef DEBUG + printf("%s:%02X %s, %s\n", cmdName, opcode, condExp, targetName); +#endif + break; + } + + case MAESTRO_IFC: + { + ENSURE_NO_MORE_ARGS(); + + if (NO_MORE_STACK) + return throwError("too many nested blocks\n"); + + StackEntry& elem = g_stack[g_stackPos++]; + elem.type = SE_IF; + elem.pos = BUF.size(); + elem.uExtra = 0; + +#ifdef DEBUG + printf("%s:%02X %s\n", cmdName, opcode, condExp); +#endif + break; + } + } + + BUF.push_back(FMT_OPCODE(opcode) | instruction); + return 0; } @@ -865,6 +970,7 @@ static const cmdTableType cmdTable[] = DEC_COMMAND(FOR, formatfor), + DEC_COMMAND(BREAKC, format2), DEC_COMMAND(CALLC, format2), DEC_COMMAND(IFC, format2), DEC_COMMAND(JMPC, format2),