//
// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
// RMAC.C - Main Application Code
-// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
+// Copyright (C) 199x Landon Dyer, 2011 - 2016 Reboot and Friends
// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
-// Source Utilised with the Kind Permission of Landon Dyer
+// Source utilised with the kind permission of Landon Dyer
//
#include "rmac.h"
int glob_flag; // Assume undefined symbols are global
int lsym_flag; // Include local symbols in object file
int sbra_flag; // Warn about possible short branches
+int prg_flag; // !=0, produce .PRG executable (2=symbols)
int legacy_flag; // Do stuff like insert code in RISC assembler
int obj_format; // Object format flag
int debug; // [1..9] Enable debugging levels
int err_flag; // '-e' specified
-int err_fd; // File to write error messages to
+int err_fd; // File to write error messages to
int rgpu, rdsp; // Assembling Jaguar GPU or DSP code
int list_fd; // File to write listing to
int regbank; // RISC register bank
int segpadsize; // Segment padding size
-int endian; // Host processor endianess
+int endian; // Host processor endianess (0 = LE, 1 = BE)
char * objfname; // Object filename pointer
char * firstfname; // First source filename
char * cmdlnexec; // Executable name, pointer to ARGV[0]
-char * searchpath; // Search path for include files
+char * searchpath; // Search path for include files
char defname[] = "noname.o"; // Default output filename
-
+int optim_flags[OPT_COUNT]; // Specific optimisations on/off matrix
//
// Manipulate file extension.
// Clobber any old extension, if requested
if (stripp)
{
- for(s=beg; *s && *s!='.'; ++s)
+ for(s=beg; *s && *s!='.'; ++s)
;
*s = '\0';
// Return 'item'nth element of semicolon-seperated pathnames specified in the
// enviroment string 's'. Copy the pathname to 'buf'. Return 0 if the 'item'
// nth path doesn't exist.
-//
+//
// ['item' ranges from 0 to N-1, where N = #elements in search path]
//
int nthpath(char * env_var, int itemno, char * buf)
" -dsymbol[=value] Define symbol\n"
" -e[errorfile] Send error messages to file, not stdout\n"
" -f[format] Output object file format\n"
+ " a: ALCYON (use this for ST)\n"
" b: BSD (use this for Jaguar)\n"
+ " e: ELF\n"
" -i[path] Directory to search for include files\n"
" -l[filename] Create an output listing file\n"
" -n Don't do things behind your back in RISC assembler\n"
" -o file Output file name\n"
+ " +o[value] Turn a specific optimisation on\n"
+ " ~o[value] Turn a specific optimisation off\n"
+ " +oall Turn all optimisations on\n"
+ " ~oall Turn all optimisations off\n"
+ " -p Create an ST .prg (without symbols)\n"
+ " -ps Create an ST .prg (with symbols)\n"
+ " Forces -fa\n"
" -r[size] Pad segments to boundary size specified\n"
" w: word (2 bytes, default alignment)\n"
" l: long (4 bytes)\n"
" d: double phrase (16 bytes)\n"
" q: quad phrase (32 bytes)\n"
" -s Warn about possible short branches\n"
+ " and applied optimisations\n"
" -u Force referenced and undefined symbols global\n"
" -v Set verbose mode\n"
+ " -x Turn on debugging mode\n"
" -y[pagelen] Set page line length (default: 61)\n"
"\n", cmdlnexec);
}
//
void DisplayVersion(void)
{
- printf("\nReboot's Macro Assembler for Atari Jaguar\n"
- "Copyright (C) 199x Landon Dyer, 2011-2015 Reboot\n"
+ printf("\n"
+ " _ __ _ __ ___ __ _ ___ \n"
+ "| '__| '_ ` _ \\ / _` |/ __|\n"
+ "| | | | | | | | (_| | (__ \n"
+ "|_| |_| |_| |_|\\__,_|\\___|\n"
+ "\nReboot's Macro Assembler\n"
+ "Copyright (C) 199x Landon Dyer, 2011-2017 Reboot\n"
"V%01i.%01i.%01i %s (%s)\n\n", MAJOR, MINOR, PATCH, __DATE__, PLATFORM);
}
-//
+//
+// Parse optimisation options
+//
+int ParseOptimization(char * optstring)
+{
+ int onoff = 0;
+
+ if (*optstring == '+')
+ onoff = 1;
+ else if (*optstring != '~')
+ return ERROR;
+
+ if ((optstring[2] == 'a' || optstring[2] == 'A')
+ && (optstring[3] == 'l' || optstring[3] == 'L')
+ && (optstring[4] == 'l' || optstring[4] == 'L'))
+ {
+ memset(optim_flags, onoff, OPT_COUNT * sizeof(int));
+ return OK;
+ }
+ else if (optstring[1] == 'o' || optstring[1] == 'O') // Turn on specific optimisation
+ {
+ int opt_no = atoi(&optstring[2]);
+
+ if ((opt_no >= 0) && (opt_no < OPT_COUNT))
+ {
+ optim_flags[opt_no] = onoff;
+ return OK;
+ }
+ else
+ return ERROR;
+ }
+ else
+ {
+ return ERROR;
+ }
+}
+
+
+//
// Process command line arguments and do an assembly
//
int Process(int argc, char ** argv)
SYM * sy; // Pointer to a symbol record
char * s; // String pointer
int fd; // File descriptor
- char fnbuf[FNSIZ]; // Filename buffer
+ char fnbuf[FNSIZ]; // Filename buffer
int i; // Iterator
errcnt = 0; // Initialise error count
switch (argv[argno][2])
{
case EOS:
- case 'b': // -fb = BSD (Jaguar Recommended)
+ case 'a': // -fa = Alcyon [the default]
+ case 'A':
+ obj_format = ALCYON;
+ break;
+ case 'b': // -fb = BSD (Jaguar Recommended: 3 out 4 jaguars recommend it!)
case 'B':
obj_format = BSD;
break;
+ case 'e': // -fe = ELF
+ case 'E':
+ obj_format = ELF;
+ break;
default:
printf("-f: unknown object format specified\n");
errcnt++;
errcnt++;
return errcnt;
}
+
objfname = argv[argno];
}
+ break;
+ case 'p': /* -p: generate ".PRG" executable output */
+ case 'P':
+ /*
+ * -p .PRG generation w/o symbols
+ * -ps .PRG generation with symbols
+ */
+ switch (argv[argno][2])
+ {
+ case EOS:
+ prg_flag = 1;
+ break;
+
+ case 's':
+ case 'S':
+ prg_flag = 2;
+ break;
+
+ default:
+ printf("-p: syntax error\n");
+ ++errcnt;
+ return errcnt;
+ }
+
+ // Enforce Alcyon object format - kind of silly
+ // to ask for .prg output without it!
+ obj_format = ALCYON;
break;
case 'r': // Pad seg to requested boundary size
case 'R':
switch(argv[argno][2])
{
- case 'w': case 'W': segpadsize = 2; break;
+ case 'w': case 'W': segpadsize = 2; break;
case 'l': case 'L': segpadsize = 4; break;
case 'p': case 'P': segpadsize = 8; break;
case 'd': case 'D': segpadsize = 16; break;
break;
}
}
+ else if (*argv[argno] == '+' || *argv[argno] == '~')
+ {
+ if (ParseOptimization(argv[argno]) != OK)
+ {
+ DisplayVersion();
+ printf("Unknown switch: %s\n\n", argv[argno]);
+ DisplayHelp();
+ errcnt++;
+ break;
+ }
+ }
else
{
// Record first filename.
firstfname = defname;
strcpy(fnbuf, firstfname);
- //fext(fnbuf, prg_flag ? ".prg" : ".o", 1);
- fext(fnbuf, ".o", 1);
+ fext(fnbuf, (prg_flag ? ".prg" : ".o"), 1);
objfname = fnbuf;
}
if (verb_flag)
{
- s = "object";
+ s = (prg_flag ? "executable" : "object");
printf("[Writing %s file: %s]\n", s, objfname);
}
{
perm_verb_flag = 0; // Clobber "permanent" verbose flag
legacy_flag = 1; // Default is legacy mode on (:-P)
+
+ // Set legacy optimisation flags to on
+ // and everything else to off
+ memset(optim_flags, 0, OPT_COUNT * sizeof(int));
+ optim_flags[OPT_ABS_SHORT] =
+ optim_flags[OPT_MOVEL_MOVEQ] =
+ optim_flags[OPT_BSR_BCC_S] = 1;
+
cmdlnexec = argv[0]; // Obtain executable name
endian = GetEndianess(); // Get processor endianess
// If commands were passed in, process them
if (argc > 1)
- return Process(argc - 1, argv + 1);
+ return Process(argc - 1, argv + 1);
DisplayVersion();
DisplayHelp();