//
-// RMAC - Reboot's Macro Assembler for all Atari computers
+// RMAC - Renamed Macro Assembler for all Atari computers
// RISCA.C - GPU/DSP Assembler
-// Copyright (C) 199x Landon Dyer, 2011-2018 Reboot and Friends
+// Copyright (C) 199x Landon Dyer, 2011-2021 Reboot and Friends
// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
// Source utilised with the kind permission of Landon Dyer
//
#define MAXINTERNCC 26 // Maximum internal condition codes
+// Useful macros
+#define EVAL_REG_RETURN_IF_ERROR(x, y) \
+x = EvaluateRegisterFromTokenStream(y); \
+\
+if (x == ERROR) \
+ return ERROR;
+
+#define EVAL_REG_RETURN_IF_ERROR_OR_NO_EOL(x, y) \
+x = EvaluateRegisterFromTokenStream(y); \
+\
+if ((x == ERROR) || (ErrorIfNotAtEOL() == ERROR)) \
+ return ERROR;
+
+#define CHECK_EOL \
+if (ErrorIfNotAtEOL() == ERROR) \
+ return ERROR;
unsigned altbankok = 0; // Ok to use alternate register bank
unsigned orgactive = 0; // RISC/6502 org directive active
malform1, malform2, malform3, malform4
};
-
//
// Function to return "malformed expression" error
// This is done mainly to remove a bunch of GOTO statements in the parser
return error("Malformed opcode, %s", malformErr[signal]);
}
-
//
// Function to return "Illegal Indexed Register" error
// Anyone trying to index something other than R14 or R15
return error("Attempted index reference with non-indexable register (r%d)", reg - KW_R0);
}
-
//
// Function to return "Illegal Indexed Register" error for EQUR scenarios
// Trying to use register value within EQUR that isn't 14 or 15
return error("Attempted index reference with non-indexable register within EQUR (%s = r%d)", sy->sname, sy->svalue);
}
-
//
// Build up & deposit RISC instruction word
//
D_word(value);
}
-
//
// Evaluate the RISC register from the token stream. Passed in value is the
// FIXUP attribute to use if the expression comes back as undefined.
//
-static int EvaluateRegisterFromTokenStream(uint32_t attr)
+static int EvaluateRegisterFromTokenStream(uint32_t fixup)
{
+ // Firstly, check to see if it's a register token and return that. No
+ // need to invoke expr() for easy cases like this.
+ if (*tok >= KW_R0 && *tok <= KW_R31)
+ {
+ int reg = *tok - KW_R0;
+ tok++;
+ return reg;
+ }
+
+ if (*tok != SYMBOL)
+ {
+ // If at this point we don't have a symbol then it's garbage. Punt.
+ return error("Expected register number or EQUREG");
+ }
+
uint64_t eval; // Expression value
WORD eattr; // Expression attributes
SYM * esym; // External symbol involved in expr.
TOKEN r_expr[EXPRSIZE]; // Expression token list
// Evaluate what's in the global "tok" buffer
+ // N.B.: We should either get a fixup or a register name from EQUR
if (expr(r_expr, &eval, &eattr, &esym) != OK)
return ERROR;
if (!(eattr & DEFINED))
{
- AddFixup(FU_WORD | attr, sloc, r_expr);
+ AddFixup(FU_WORD | fixup, sloc, r_expr);
return 0;
}
return error(reg_err);
}
-
//
// Do RISC code generation
//
int indexed; // Indexed register flag
uint64_t eval; // Expression value
- uint16_t eattr; // Expression attributes
- SYM * esym; // External symbol involved in expr.
+ uint16_t eattr; // Expression attributes
+ SYM * esym = NULL; // External symbol involved in expr.
TOKEN r_expr[EXPRSIZE]; // Expression token list
// Get opcode parameter and type
// ABS, MIRROR, NEG, NOT, PACK, RESMAC, SAT8, SAT16, SAT16S, SAT24, SAT32S,
// UNPACK
case RI_ONE:
- reg2 = EvaluateRegisterFromTokenStream(FU_REGTWO);
- at_eol();
+ EVAL_REG_RETURN_IF_ERROR_OR_NO_EOL(reg2, FU_REGTWO);
DepositRISCInstructionWord(parm, parm >> 6, reg2);
break;
if (parm == 37)
altbankok = 1; // MOVEFA
- reg1 = EvaluateRegisterFromTokenStream(FU_REGONE);
+ EVAL_REG_RETURN_IF_ERROR(reg1, FU_REGONE);
CHECK_COMMA;
if (parm == 36)
altbankok = 1; // MOVETA
- reg2 = EvaluateRegisterFromTokenStream(FU_REGTWO);
- at_eol();
+ EVAL_REG_RETURN_IF_ERROR_OR_NO_EOL(reg2, FU_REGTWO);
DepositRISCInstructionWord(parm, reg1, reg2);
break;
}
else
{
+ if (esym && (esym->sattre & EQUATEDREG))
+ return error("equated register seen for immediate value");
+
+ if (eattr & RISCREG)
+ return error("register seen for immediate value");
+
if (((int)eval < reg1) || ((int)eval > reg2))
- return error("constant out of range (%d to %d", reg1, reg2);
+ return error("constant out of range (%d to %d)", reg1, reg2);
if (parm & SUB32)
reg1 = 32 - (int)eval;
}
CHECK_COMMA;
- reg2 = EvaluateRegisterFromTokenStream(FU_REGTWO);
- at_eol();
+ EVAL_REG_RETURN_IF_ERROR_OR_NO_EOL(reg2, FU_REGTWO);
DepositRISCInstructionWord(parm, reg1, reg2);
break;
}
CHECK_COMMA;
- reg2 = EvaluateRegisterFromTokenStream(FU_REGTWO);
- at_eol();
+ EVAL_REG_RETURN_IF_ERROR_OR_NO_EOL(reg2, FU_REGTWO);
DepositRISCInstructionWord(parm, 0, reg2);
val = WORDSWAP32(eval);
else
{
parm = 34;
- reg1 = EvaluateRegisterFromTokenStream(FU_REGONE);
+ EVAL_REG_RETURN_IF_ERROR(reg1, FU_REGONE);
}
CHECK_COMMA;
- reg2 = EvaluateRegisterFromTokenStream(FU_REGTWO);
- at_eol();
+ EVAL_REG_RETURN_IF_ERROR_OR_NO_EOL(reg2, FU_REGTWO);
DepositRISCInstructionWord(parm, reg1, reg2);
break;
if (!indexed)
{
- reg1 = EvaluateRegisterFromTokenStream(FU_REGONE);
+ EVAL_REG_RETURN_IF_ERROR(reg1, FU_REGONE);
}
else
{
if (indexed)
{
- reg1 = EvaluateRegisterFromTokenStream(FU_REGONE);
+ EVAL_REG_RETURN_IF_ERROR(reg1, FU_REGONE);
}
else
{
}
else
{
- reg1 = EvaluateRegisterFromTokenStream(FU_REGONE);
+ EVAL_REG_RETURN_IF_ERROR(reg1, FU_REGONE);
}
}
tok++;
CHECK_COMMA;
- reg2 = EvaluateRegisterFromTokenStream(FU_REGTWO);
- at_eol();
+ EVAL_REG_RETURN_IF_ERROR_OR_NO_EOL(reg2, FU_REGTWO);
DepositRISCInstructionWord(parm, reg1, reg2);
break;
// Rn,(Rn) = 47 / Rn,(R14/R15+n) = 49/50 / Rn,(R14/R15+Rn) = 60/61
case RI_STORE:
parm = 47;
- reg1 = EvaluateRegisterFromTokenStream(FU_REGONE);
+ EVAL_REG_RETURN_IF_ERROR(reg1, FU_REGONE);
CHECK_COMMA;
if (*tok != '(')
if (!indexed)
{
- reg2 = EvaluateRegisterFromTokenStream(FU_REGTWO);
+ EVAL_REG_RETURN_IF_ERROR(reg2, FU_REGTWO);
}
else
{
if (indexed)
{
- reg2 = EvaluateRegisterFromTokenStream(FU_REGTWO);
+ EVAL_REG_RETURN_IF_ERROR(reg2, FU_REGTWO);
}
else
{
}
else
{
- reg2 = EvaluateRegisterFromTokenStream(FU_REGTWO);
+ EVAL_REG_RETURN_IF_ERROR(reg2, FU_REGTWO);
}
}
return MalformedOpcode(MALF_RPAREN);
tok++;
- at_eol();
+ CHECK_EOL;
DepositRISCInstructionWord(parm, reg2, reg1);
break;
return MalformedOpcode(MALF_LPAREN);
tok++;
- reg1 = EvaluateRegisterFromTokenStream(FU_REGONE);
+ EVAL_REG_RETURN_IF_ERROR(reg1, FU_REGONE);
if (*tok != ')')
return MalformedOpcode(MALF_RPAREN);
tok++;
CHECK_COMMA;
- reg2 = EvaluateRegisterFromTokenStream(FU_REGTWO);
- at_eol();
+ EVAL_REG_RETURN_IF_ERROR_OR_NO_EOL(reg2, FU_REGTWO);
DepositRISCInstructionWord(parm, reg1, reg2);
break;
// STOREB/STOREP/STOREW Rn,(Rn)
case RI_STOREN:
- reg1 = EvaluateRegisterFromTokenStream(FU_REGONE);
+ EVAL_REG_RETURN_IF_ERROR(reg1, FU_REGONE);
CHECK_COMMA;
if (*tok != '(')
return MalformedOpcode(MALF_LPAREN);
tok++;
- reg2 = EvaluateRegisterFromTokenStream(FU_REGTWO);
+ EVAL_REG_RETURN_IF_ERROR(reg2, FU_REGTWO);
if (*tok != ')')
return MalformedOpcode(MALF_RPAREN);
tok++;
- at_eol();
+ CHECK_EOL;
DepositRISCInstructionWord(parm, reg2, reg1);
break;
return MalformedOpcode(MALF_LPAREN);
tok++;
- reg2 = EvaluateRegisterFromTokenStream(FU_REGTWO);
+ EVAL_REG_RETURN_IF_ERROR(reg2, FU_REGTWO);
if (*tok != ')')
return MalformedOpcode(MALF_RPAREN);
tok++;
- at_eol();
+ CHECK_EOL;
}
DepositRISCInstructionWord(parm, reg2, reg1);
lastOpcode = type;
return 0;
}
-