Add support for BREAKC/CALLC/IFC/JMPC

This commit is contained in:
fincs 2014-12-15 22:59:06 +01:00
parent af4f62dab0
commit 19f705076a
2 changed files with 111 additions and 2 deletions

View File

@ -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.

View File

@ -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),