//
-// 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
//
#include "expr.h"
#include "mark.h"
#include "procln.h"
+#include "rmac.h"
#include "sect.h"
#include "token.h"
#define DEF_MR // Declare keyword values
#include "risckw.h" // Incl. generated risc keywords
-#define DEF_KW // Declare keyword values
-#include "kwtab.h" // Incl. generated keyword tables & defs
+#define DEF_REGRISC
+#include "riscregs.h" // Incl. generated keyword tables & defs
#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
{ MR_NORMI, RI_TWO, 56 },
{ MR_NOP, RI_NONE, 57 },
{ MR_SAT24, RI_ONE, 62 },
- { MR_UNPACK, RI_ONE, 63 + GPUONLY | (0 << 6) },
- { MR_PACK, RI_ONE, 63 + GPUONLY | (1 << 6) },
+ { MR_UNPACK, RI_ONE, 63 + GPUONLY | (1 << 6) },
+ { MR_PACK, RI_ONE, 63 + GPUONLY | (0 << 6) },
{ MR_ADDQMOD, RI_NUM_32, 63 + DSPONLY },
{ MR_MOVE, RI_MOVE, 0 },
{ MR_LOAD, RI_LOAD, 0 },
malform1, malform2, malform3, malform4
};
-
-//
-// Convert a string to uppercase
-//
-static void strtoupper(char * s)
-{
- while (*s)
- *s++ &= 0xDF;
-}
-
-
//
// 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
//
static inline int IllegalIndexedRegister(int reg)
{
- return error("Attempted index reference with non-indexable register (r%d)", reg - KW_R0);
+ return error("Attempted index reference with non-indexable register (r%d)", reg - REGRISC_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
//
}
int value = ((opcode & 0x3F) << 10) + ((reg1 & 0x1F) << 5) + (reg2 & 0x1F);
+ GENLINENOSYM();
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.
+ int reg = *tok & 255;
+ if (reg >= REGRISC_R0 && reg <= REGRISC_R31)
+ {
+ reg -= REGRISC_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;
}
- // If we got a register in range (0-31), return it
- if (eval <= 31)
- return (int)eval;
-
- // Otherwise, it's out of range & we flag an error
- return error(reg_err);
+ // We shouldn't get here, that should not be legal
+ interror(9);
+ return 0; // Not that this will ever execute, but let's be nice and pacify gcc warnings
}
-
//
// 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);
// PC,Rd or Rs,Rd
case RI_MOVE:
- if (*tok == KW_PC)
+ if (*tok == REGRISC_PC)
{
parm = 51;
reg1 = 0;
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 ((tok[1] == '+') || (tok[1] == '-'))
{
// Trying to make indexed call
- if ((*tok == KW_R14) || (*tok == KW_R15))
- indexed = (*tok - KW_R0);
+ if ((*tok == REGRISC_R14) || (*tok == REGRISC_R15))
+ indexed = (*tok - REGRISC_R0);
else
return IllegalIndexedRegister(*tok);
}
- if (*tok == SYMBOL)
- {
- sy = lookup(string[tok[1]], LABEL, 0);
-
- if (!sy)
- {
- error(reg_err);
- return ERROR;
- }
-
- if (sy->sattre & EQUATEDREG)
- {
- if ((tok[2] == '+') || (tok[2] == '-'))
- {
- if ((sy->svalue & 0x1F) == 14 || (sy->svalue & 0x1F) == 15) {
- indexed = (sy->svalue & 0x1F);
- tok++;
- }
- else
- return IllegalIndexedRegisterEqur(sy);
- }
- }
- }
-
if (!indexed)
{
- reg1 = EvaluateRegisterFromTokenStream(FU_REGONE);
+ EVAL_REG_RETURN_IF_ERROR(reg1, FU_REGONE);
}
else
{
parm = (WORD)(reg1 - 14 + 58);
tok++;
- if ((*tok >= KW_R0) && (*tok <= KW_R31))
+ if ((*tok >= REGRISC_R0) && (*tok <= REGRISC_R31))
indexed = 1;
if (*tok == SYMBOL)
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 != '(')
tok++;
indexed = 0;
- if (((*tok == KW_R14) || (*tok == KW_R15)) && (tok[1] != ')'))
- indexed = *tok - KW_R0;
-
- if (*tok == SYMBOL)
- {
- sy = lookup(string[tok[1]], LABEL, 0);
-
- if (!sy)
- {
- error(reg_err);
- return ERROR;
- }
-
- if (sy->sattre & EQUATEDREG)
- {
- if (((sy->svalue & 0x1F) == 14 || (sy->svalue & 0x1F) == 15)
- && (tok[2] != ')'))
- {
- indexed = (sy->svalue & 0x1F);
- tok++;
- }
- }
- }
+ if (((*tok == REGRISC_R14) || (*tok == REGRISC_R15)) && (tok[1] != ')'))
+ indexed = *tok - REGRISC_R0;
if (!indexed)
{
- reg2 = EvaluateRegisterFromTokenStream(FU_REGTWO);
+ EVAL_REG_RETURN_IF_ERROR(reg2, FU_REGTWO);
}
else
{
parm = (WORD)(reg2 - 14 + 60);
tok++;
- if ((*tok >= KW_R0) && (*tok <= KW_R31))
+ if ((*tok >= REGRISC_R0) && (*tok <= REGRISC_R31))
indexed = 1;
if (*tok == SYMBOL)
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;
}
-