-//
-// Lists of registers may also be mentioned; they just take up space. Good for "documentation"
-// purposes.
-//
-// .cargs a6,.arg1, .arg2, .arg3...
-//
-// The symbols are ABS and EQUATED.
-// -------------------------------------------------------------------------------------------------
-//
-
-int d_cargs(void) {
- VALUE eval;
- WORD rlist;
- SYM *sy;
- char *p;
- int env;
- int i;
-
- if(rgpu || rdsp)
- return(error("directive forbidden in gpu/dsp mode"));
-
- if(*tok == '#') {
- ++tok;
- if(abs_expr(&eval) != OK)
- return(0);
- if(*tok == ',') // Eat comma if it's there
- ++tok;
- } else
- eval = 4;
-
- for(;;) {
- if(*tok == SYMBOL) {
- p = (char *)tok[1];
- if(*p == '.')
- env = curenv;
- else
- env = 0;
-
- sy = lookup(p, LABEL, env);
- if(sy == NULL) {
- sy = newsym(p, LABEL, env);
- sy->sattr = 0;
- } else
- if(sy->sattr & DEFINED)
- return(errors("multiply-defined label '%s'", p));
-
- // Put symbol in "order of definition" list
- if(!(sy->sattr & SDECLLIST)) sym_decl(sy);
-
- sy->sattr |= ABS|DEFINED|EQUATED;
- sy->svalue = eval;
- tok += 2;
-
- switch((int)*tok) {
- case DOTL:
- eval += 2;
- case DOTB:
- case DOTW:
- ++tok;
- }
- eval += 2;
- } else
- if(*tok >= KW_D0 && *tok <= KW_A7) {
- if(reglist(&rlist) < 0)
- return(0);
- for(i = 0; i++ < 16; rlist >>= 1)
- if(rlist & 1)
- eval += 4;
- } else
- switch((int)*tok) {
- case KW_USP:
- case KW_SSP:
- case KW_PC:
- eval += 2;
- // FALLTHROUGH
- case KW_SR:
- case KW_CCR:
- eval += 2;
- ++tok;
- break;
- case EOL:
- return(0);
- default:
- return(error(".cargs syntax"));
- }
-
- if(*tok == ',')
- ++tok;
- }
+//
+// Lists of registers may also be mentioned; they just take up space. Good for
+// "documentation" purposes:
+//
+// .cargs a6, .arg1, .arg2, .arg3...
+//
+// Symbols thus created are ABS and EQUATED.
+//
+int d_cargs(void)
+{
+ uint64_t eval = 4; // Default to 4 if no offset specified (to account for
+ // return address)
+ WORD rlist;
+ SYM * symbol;
+ char * p;
+ int env;
+ int i;
+
+ if (rgpu || rdsp)
+ return error("directive forbidden in gpu/dsp mode");
+
+ if (*tok == '#')
+ {
+ tok++;
+
+ if (abs_expr(&eval) != OK)
+ return 0;
+
+ // Eat the comma, if it's there
+ if (*tok == ',')
+ tok++;
+ }
+
+ for(;;)
+ {
+ if (*tok == SYMBOL)
+ {
+ p = string[tok[1]];
+
+ // Set env to either local (dot prefixed) or global scope
+ env = (*p == '.' ? curenv : 0);
+ symbol = lookup(p, LABEL, env);
+
+ if (symbol == NULL)
+ {
+ symbol = NewSymbol(p, LABEL, env);
+ symbol->sattr = 0;
+ }
+ else if (symbol->sattr & DEFINED)
+ return error("multiply-defined label '%s'", p);
+
+ // Put symbol in "order of definition" list
+ AddToSymbolDeclarationList(symbol);
+
+ symbol->sattr |= (ABS | DEFINED | EQUATED);
+ symbol->svalue = eval;
+ tok += 2;
+
+ // What this does is eat any dot suffixes attached to a symbol. If
+ // it's a .L, it adds 4 to eval; if it's .W or .B, it adds 2. If
+ // there is no dot suffix, it assumes a size of 2.
+ switch ((int)*tok)
+ {
+ case DOTL:
+ eval += 2;
+ case DOTB:
+ case DOTW:
+ tok++;
+ }
+
+ eval += 2;
+ }
+ else if (*tok >= REG68_D0 && *tok <= REG68_A7)
+ {
+ if (reglist(&rlist) < 0)
+ return 0;
+
+ for(i=0; i<16; i++, rlist>>=1)
+ {
+ if (rlist & 1)
+ eval += 4;
+ }
+ }
+ else
+ {
+ switch ((int)*tok)
+ {
+ case REG68_USP:
+ case REG68_SSP:
+ case REG68_PC:
+ eval += 2;
+ // FALLTHROUGH
+ case REG68_SR:
+ case REG68_CCR:
+ eval += 2;
+ tok++;
+ break;
+ case EOL:
+ return 0;
+ default:
+ return error(".cargs syntax");
+ }
+ }
+
+ // Eat commas in between each argument, if they exist
+ if (*tok == ',')
+ tok++;
+ }
+}
+
+
+//
+// .cstruct [#offset], symbol[.size], ...
+//
+// Lists of registers may also be mentioned; they just take up space. Good for
+// "documentation" purposes:
+//
+// .cstruct a6, .arg1, .arg2, .arg3...
+//
+// Symbols thus created are ABS and EQUATED. Note that this is for
+// compatibility with VBCC and the Remover's library. Thanks to GroovyBee for
+// the suggestion.
+//
+int d_cstruct(void)
+{
+ uint64_t eval = 0; // Default, if no offset specified, is zero
+ WORD rlist;
+ SYM * symbol;
+ char * symbolName;
+ int env;
+ int i;
+
+ if (rgpu || rdsp)
+ return error("directive forbidden in gpu/dsp mode");
+
+ if (*tok == '#')
+ {
+ tok++;
+
+ if (abs_expr(&eval) != OK)
+ return 0;
+
+ // Eat the comma, if it's there
+ if (*tok == ',')
+ tok++;
+ }
+
+ for(;;)
+ {
+ if (*tok == SYMBOL)
+ {
+ symbolName = string[tok[1]];
+
+ // Set env to either local (dot prefixed) or global scope
+ env = (symbolName[0] == '.' ? curenv : 0);
+ symbol = lookup(symbolName, LABEL, env);
+
+ // If the symbol wasn't found, then define it. Otherwise, throw an
+ // error.
+ if (symbol == NULL)
+ {
+ symbol = NewSymbol(symbolName, LABEL, env);
+ symbol->sattr = 0;
+ }
+ else if (symbol->sattr & DEFINED)
+ return error("multiply-defined label '%s'", symbolName);
+
+ // Put symbol in "order of definition" list
+ AddToSymbolDeclarationList(symbol);
+
+ tok += 2;
+
+ // Adjust label start address if it's a word or a long, as a byte
+ // label might have left us on an odd address.
+ switch ((int)*tok)
+ {
+ case DOTW:
+ case DOTL:
+ eval += eval & 0x01;
+ }
+
+ symbol->sattr |= (ABS | DEFINED | EQUATED);
+ symbol->svalue = eval;
+
+ // Check for dot suffixes and adjust space accordingly (longs and
+ // words on an odd boundary get bumped to the next word aligned
+ // address). If no suffix, then throw an error.
+ switch ((int)*tok)
+ {
+ case DOTL:
+ eval += 4;
+ break;
+ case DOTW:
+ eval += 2;
+ break;
+ case DOTB:
+ eval += 1;
+ break;
+ default:
+ return error("Symbol missing dot suffix in .cstruct construct");
+ }
+
+ tok++;
+ }
+ else if (*tok >= REG68_D0 && *tok <= REG68_A7)
+ {
+ if (reglist(&rlist) < 0)
+ return 0;
+
+ for(i=0; i<16; i++, rlist>>=1)
+ {
+ if (rlist & 1)
+ eval += 4;
+ }
+ }
+ else
+ {
+ switch ((int)*tok)
+ {
+ case REG68_USP:
+ case REG68_SSP:
+ case REG68_PC:
+ eval += 2;
+ // FALLTHROUGH
+ case REG68_SR:
+ case REG68_CCR:
+ eval += 2;
+ tok++;
+ break;
+ case EOL:
+ return 0;
+ default:
+ return error(".cstruct syntax");
+ }
+ }
+
+ // Eat commas in between each argument, if they exist
+ if (*tok == ',')
+ tok++;
+ }
+}
+
+
+//
+// Define start of OP object list (allows the use of ORG)
+//
+int d_objproc(void)
+{
+ if ((cursect != TEXT) && (cursect != DATA))
+ {
+ error(".objproc can only be used in the TEXT or DATA segments");
+ return ERROR;
+ }
+
+ // If previous section was DSP or 68000 then we need to reset ORG'd
+ // Addresses
+ if (!robjproc)
+ {
+ orgactive = 0;
+ orgwarning = 0;
+ }
+
+ robjproc = 1; // Set OP assembly
+ rgpu = 0; // Unset GPU assembly
+ rdsp = 0; // Unset DSP assembly
+ dsp56001 = 0; // Unset 56001 assembly
+ //used_architectures |= MOP; // TODO: Should OP have its own dedicated section in the long run?
+ return OK;
+}
+
+
+//
+// Undefine a macro - .undefmac macname [, macname...]
+//
+int undmac1(char * p)
+{
+ SYM * symbol = lookup(p, MACRO, 0);
+
+ // If the macro symbol exists, cause it to disappear
+ if (symbol != NULL)
+ symbol->stype = (BYTE)SY_UNDEF;
+
+ return OK;
+}
+
+
+int d_undmac(void)
+{
+ symlist(undmac1);
+ return 0;
+}
+
+
+int d_jpad(void)
+{
+ warn("JPAD directive is deprecated/non-functional");
+ return OK;
+}
+
+
+int d_nojpad(void)
+{
+ warn("NOJPAD directive is deprecated/non-functional");
+ return OK;
+}
+
+
+int d_gpumain(void)
+{
+ return error("What the hell? Do you think we adhere to the Goof standard?");
+}
+
+
+//
+// .opt - turn a specific (or all) optimisation on or off
+//
+int d_opt(void)
+{
+ while (*tok != EOL)
+ {
+ if (*tok == STRING)
+ {
+ tok++;
+ char * tmpstr = string[*tok++];
+
+ if (ParseOptimization(tmpstr) != OK)
+ return error("unknown optimization flag '%s'", tmpstr);
+ }
+ else
+ return error(".opt directive needs every switch enclosed inside quotation marks");
+ }
+
+ return OK;