X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?p=rmac;a=blobdiff_plain;f=rmac.c;h=4772d203bd93d612f5e9e6a7121ae37e98fc9786;hp=4e8234603be2f6f85a61d1fe69fc06630d353651;hb=HEAD;hpb=9d0b53158275f8f9f542fb4d4a873d54789fe027 diff --git a/rmac.c b/rmac.c index 4e82346..17715f7 100644 --- a/rmac.c +++ b/rmac.c @@ -1,51 +1,77 @@ // -// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System +// RMAC - Renamed Macro Assembler for all Atari computers // RMAC.C - Main Application Code -// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends +// Copyright (C) 199x Landon Dyer, 2011-2022 Reboot and Friends // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986 // Source utilised with the kind permission of Landon Dyer // #include "rmac.h" +#include "6502.h" +#include "debug.h" +#include "direct.h" +#include "dsp56k.h" #include "error.h" -#include "listing.h" -#include "procln.h" -#include "token.h" #include "expr.h" -#include "sect.h" +#include "listing.h" #include "mark.h" #include "macro.h" +#include "object.h" +#include "procln.h" #include "riscasm.h" -#include "direct.h" -#include "version.h" -#include "debug.h" +#include "sect.h" #include "symbol.h" -#include "object.h" +#include "token.h" +#include "version.h" int perm_verb_flag; // Permanently verbose, interactive mode int list_flag; // "-l" listing flag on command line +int list_pag = 1; // Enable listing pagination by default int verb_flag; // Be verbose about what's going on -int as68_flag; // as68 kludge mode +int m6502; // 1, assembling 6502 code 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 lsym_flag; // Include local symbols in object file (ALWAYS true) +int dsym_flag; // Gen debug syms (Requires obj_format = BSD) +int optim_warn_flag; // Warn about possible short branches int prg_flag; // !=0, produce .PRG executable (2=symbols) +int prg_extend; // !=0, output extended .PRG 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 robjproc; // Assembling Jaguar Object Processor code +int dsp56001; // Assembling DSP 56001 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) +int *regbase; // Points to current DFA register table (base) +int *regtab; // Points to current DFA register table (tab) +int *regcheck; // Points to current DFA register table (check) +int *regaccept; // Points to current DFA register table (accept) 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 searchpatha[512] = { 0 }; // Buffer to hold searchpath when specified +char * searchpath = NULL; // Search path for include files char defname[] = "noname.o"; // Default output filename -int optim_flags[OPT_COUNT]; // Specific optimisations on/off matrix +int optim_flags[OPT_COUNT_ALL] = { 0 }; // Specific optimisations on/off matrix +int activecpu = CPU_68000; // Active 68k CPU (68000 by default) +int activefpu = FPU_NONE; // Active FPU (none by default) +int org68k_active = 0; // .org switch for 68k (only with RAW output format) +uint32_t org68k_address; // .org for 68k +int correctMathRules; // 1, use C operator precedence in expressions +uint32_t used_architectures; // Bitmask that records exactly which architectures were used during assembly + +// +// Convert a string to uppercase +// +void strtoupper(char * s) +{ + while (*s) + *s++ &= 0xDF; +} // // Manipulate file extension. @@ -67,7 +93,7 @@ char * fext(char * name, char * extension, int stripp) // Clobber any old extension, if requested if (stripp) { - for(s=beg; *s && *s!='.'; ++s) + for(s=beg; *s && *s!='.'; ++s) ; *s = '\0'; @@ -79,12 +105,23 @@ char * fext(char * name, char * extension, int stripp) return name; } +static int is_sep(char c) +{ + const char *seps = PATH_SEPS; + + for (seps = PATH_SEPS; *seps; seps++) { + if (*seps == c) + return 1; + } + + return 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) @@ -98,13 +135,13 @@ int nthpath(char * env_var, int itemno, char * buf) return 0; while (itemno--) - while (*s != EOS && *s++ != ';') + while (*s != EOS && !is_sep(*s++)) ; if (*s == EOS) return 0; - while (*s != EOS && *s != ';') + while (*s != EOS && !is_sep(*s)) *buf++ = *s++; *buf++ = EOS; @@ -112,7 +149,6 @@ int nthpath(char * env_var, int itemno, char * buf) return 1; } - // // Display command line help // @@ -123,22 +159,46 @@ void DisplayHelp(void) "\n" "Options:\n" " -? or -h Display usage information\n" - " -dsymbol[=value] Define symbol\n" + " -dsymbol[=value] Define symbol (with optional value, default=0)\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" + " a: ALCYON\n" " b: BSD (use this for Jaguar)\n" + " c: PRG (C64)\n" + " e: ELF\n" + " p: P56 (use this for DSP56001 only)\n" + " l: LOD (use this for DSP56001 only)\n" + " x: com/exe/xex (Atari 800)\n" + " r: absolute address\n" + " -g Output source level debug information (BSD object only)\n" " -i[path] Directory to search for include files\n" " -l[filename] Create an output listing file\n" + " -l*[filename] Create an output listing file without pagination\n" + " -m[cpu] Select default CPU. Available options:\n" + " 68000, 68020, 68030, 68040, 68060, 6502, tom, jerry, 56001\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" + " Available optimisation switches:\n" + " o0: Absolute long addresses to word\n" + " o1: move.l #x,dn/an to moveq\n" + " o2: Word branches to short\n" + " o3: Outer displacement 0(an) to (an)\n" + " o4: lea size(An),An to addq #size,An\n" + " o5: 68020+ Absolute long base/outer disp. to word\n" + " o6: Null branches to NOP\n" + " o7: clr.l Dx to moveq #0,Dx\n" + " o8: adda.w/l #x,Dy to addq.w/l #x,Dy\n" + " o9: adda.w/l #x,Ay to lea x(Dy),Ay\n" + " o10: 56001 Use short format for immediate values if possible\n" + " o11: 56001 Auto convert short addressing mode to long (default: on)\n" + " o30: Enforce PC relative (alternative name: op)\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" + " -p Create an ST .prg (without symbols). Forces -fa\n" + " -ps Create an ST .prg (with symbols). Forces -fa\n" + " -px Create an ST .prg (with exsymbols). Forces -fa\n" " -r[size] Pad segments to boundary size specified\n" " w: word (2 bytes, default alignment)\n" " l: long (4 bytes)\n" @@ -151,6 +211,7 @@ void DisplayHelp(void) " -v Set verbose mode\n" " -x Turn on debugging mode\n" " -y[pagelen] Set page line length (default: 61)\n" + " -4 Use C style operator precedence\n" "\n", cmdlnexec); } @@ -165,12 +226,11 @@ void DisplayVersion(void) "| '__| '_ ` _ \\ / _` |/ __|\n" "| | | | | | | | (_| | (__ \n" "|_| |_| |_| |_|\\__,_|\\___|\n" - "\nReboot's Macro Assembler\n" - "Copyright (C) 199x Landon Dyer, 2011-2015 Reboot\n" + "\nRenamed Macro Assembler\n" + "Copyright (C) 199x Landon Dyer, 2011-2022 Reboot and Friends\n" "V%01i.%01i.%01i %s (%s)\n\n", MAJOR, MINOR, PATCH, __DATE__, PLATFORM); } - // // Parse optimisation options // @@ -178,38 +238,104 @@ 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')) + while (*optstring) { - 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 (*optstring == '+') + onoff = 1; + else if (*optstring != '~') + return ERROR; + + if (optstring[2] == 0) + return error(".opt called with zero arguments"); - if ((opt_no >= 0) && (opt_no < OPT_COUNT)) + if ((optstring[2] == 'a' || optstring[2] == 'A') + && (optstring[3] == 'l' || optstring[3] == 'L') + && (optstring[4] == 'l' || optstring[4] == 'L')) { - optim_flags[opt_no] = onoff; - return OK; + memset(optim_flags, onoff, OPT_COUNT * sizeof(int)); + optstring += 5; + } + else if (optstring[1] == 'o' || optstring[1] == 'O') // Turn on specific optimisation + { + if (optstring[2] == 'p' || optstring[2] == 'P') + { + optim_flags[OPT_PC_RELATIVE] = onoff; + optstring += 3; + } + else + { + int opt_no = atoi(&optstring[2]); + + if ((opt_no >= 0) && (opt_no < OPT_COUNT)) + { + optim_flags[opt_no] = onoff; + optstring += 3; + + // If opt_no is 2 digits then consume an extra character. + // Sounds a bit sleazy but we know we're not going to hit + // more than 100 optimisation switches so this should be + // fine. If we do hit that number then it'll probably be + // time to burn the whole codebase and start from scratch. + if (opt_no > 9) + optstring++; + } + else + return ERROR; + } } else + { return ERROR; + } + + if (*optstring == ',') + optstring++; } - else + return OK; +} + +static void ProcessFile(int fd, char *fname) +{ + char *dbgname = fname; + + if (NULL == fname) { - return ERROR; + fname = defname; // Kludge first filename + dbgname = "(stdin)"; } + + // First file operations: + if (firstfname == NULL) + { + // Record first filename. + firstfname = fname; + + // Validate option compatibility + if (dsym_flag) + { + if (obj_format != BSD) + { + printf("-g: debug information only supported with BSD object file format\n"); + dsym_flag = 0; + errcnt++; + } + else + { + GenMainFileSym(dbgname); + } + } + } + + include(fd, dbgname); + Assemble(); } +extern int reg68base[53]; +extern int reg68tab[222]; +extern int reg68check[222]; +extern int reg68accept[222]; -// +// // Process command line arguments and do an assembly // int Process(int argc, char ** argv) @@ -218,34 +344,42 @@ 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 - listing = 0; // Initialise listing level - list_flag = 0; // Initialise listing flag - verb_flag = perm_verb_flag; // Initialise verbose flag - as68_flag = 0; // Initialise as68 kludge mode - glob_flag = 0; // Initialise .globl flag - sbra_flag = 0; // Initialise short branch flag - debug = 0; // Initialise debug flag - searchpath = NULL; // Initialise search path - objfname = NULL; // Initialise object filename - list_fname = NULL; // Initialise listing filename - err_fname = NULL; // Initialise error filename - obj_format = BSD; // Initialise object format - firstfname = NULL; // Initialise first filename - err_fd = ERROUT; // Initialise error file descriptor - err_flag = 0; // Initialise error flag - rgpu = 0; // Initialise GPU assembly flag - rdsp = 0; // Initialise DSP assembly flag + int current_path_index = 0; // Iterator for search paths + + errcnt = 0; // Initialize error count + listing = 0; // Initialize listing level + list_flag = 0; // Initialize listing flag + verb_flag = perm_verb_flag; // Initialize verbose flag + glob_flag = 0; // Initialize .globl flag + optim_warn_flag = 0; // Initialize short branch flag + debug = 0; // Initialize debug flag + objfname = NULL; // Initialize object filename + list_fname = NULL; // Initialize listing filename + err_fname = NULL; // Initialize error filename + obj_format = BSD; // Initialize object format + firstfname = NULL; // Initialize first filename + err_fd = ERROUT; // Initialize error file descriptor + err_flag = 0; // Initialize error flag + rgpu = 0; // Initialize GPU assembly flag + rdsp = 0; // Initialize DSP assembly flag + robjproc = 0; // Initialize OP assembly flag lsym_flag = 1; // Include local symbols in object file - regbank = BANK_N; // No RISC register bank specified + dsym_flag = 0; // No debug sym generation by default orgactive = 0; // Not in RISC org section orgwarning = 0; // No ORG warning issued - segpadsize = 2; // Initialise segment padding size - - // Initialise modules + segpadsize = 2; // Initialize segment padding size + dsp_orgmap[0].start = 0; // Initialize 56001 org initial address + dsp_orgmap[0].memtype = ORG_P; // Initialize 56001 org start segment + m6502 = 0; // 6502 mode off by default + regbase = reg68base; // Initialise DFA register tables + regtab = reg68tab; // Idem + regcheck = reg68check; // Idem + regaccept = reg68accept; // Idem + correctMathRules = 0; // respect operator precedence + used_architectures = 0; // Initialise used architectures bitfield + // Initialize modules InitSymbolTable(); // Symbol table InitTokenizer(); // Tokenizer InitLineProcessor(); // Line processor @@ -254,14 +388,18 @@ int Process(int argc, char ** argv) InitMark(); // Mark tape-recorder InitMacro(); // Macro processor InitListing(); // Listing generator + Init6502(); // 6502 assembler // Process command line arguments and assemble source files - for(argno=0; argnosattr = DEFINED | EQUATED | ABS; - sy->svalue = (*s ? (VALUE)atoi(s) : 0); + sy->svalue = (*s ? (uint64_t)atoi(s) : 0); break; case 'e': // Redirect error message output case 'E': @@ -304,10 +442,34 @@ int Process(int argc, char ** argv) case 'A': obj_format = ALCYON; break; - case 'b': // -fb = BSD (Jaguar Recommended) + case 'b': // -fb = BSD (Jaguar Recommended: 3 out 4 jaguars recommend it!) case 'B': obj_format = BSD; break; + case 'c': + case 'C': + obj_format = C64PRG; + break; + case 'e': // -fe = ELF + case 'E': + obj_format = ELF; + break; + case 'l': // -fl = LOD + case 'L': + obj_format = LOD; + break; + case 'p': // -fp = P56 + case 'P': + obj_format = P56; + break; + case 'x': // -fx = COM/EXE/XEX + case 'X': + obj_format = XEX; + break; + case 'r': // -fr = Absolute address + case 'R': + obj_format = RAW; + break; default: printf("-f: unknown object format specified\n"); errcnt++; @@ -316,19 +478,85 @@ int Process(int argc, char ** argv) break; case 'g': // Debugging flag case 'G': - printf("Debugging flag (-g) not yet implemented\n"); + dsym_flag = 1; break; case 'i': // Set directory search path case 'I': - searchpath = argv[argno] + 2; + { + strcat(searchpatha, argv[argno] + 2); + strcat(searchpatha, ";"); + searchpath = searchpatha; + + // Check to see if include paths actually exist + char current_path[256]; + + for(i=current_path_index; nthpath("RMACPATH", i, current_path)!=0; i++) + { + if (strlen(current_path) > 0) + { + DIR * test = opendir(current_path); + + if (test == NULL) + { + printf("Invalid include path: %s\n", current_path); + errcnt++; + return errcnt; + } + + closedir(test); + } + } + + current_path_index = i - 1; break; + } case 'l': // Produce listing file case 'L': - list_fname = argv[argno] + 2; + if (*(argv[argno] + 2) == '*') + { + list_fname = argv[argno] + 3; + list_pag = 0; // Special case - turn off pagination + } + else + { + list_fname = argv[argno] + 2; + } + listing = 1; list_flag = 1; lnsave++; break; + case 'm': + case 'M': + if (strcmp(argv[argno] + 2, "68000") == 0) + d_68000(); + else if (strcmp(argv[argno] + 2, "68020") == 0) + d_68020(); + else if (strcmp(argv[argno] + 2, "68030") == 0) + d_68030(); + else if (strcmp(argv[argno] + 2, "68040") == 0) + d_68040(); + else if (strcmp(argv[argno] + 2, "68060") == 0) + d_68060(); + else if (strcmp(argv[argno] + 2, "68881") == 0) + d_68881(); + else if (strcmp(argv[argno] + 2, "68882") == 0) + d_68882(); + else if (strcmp(argv[argno] + 2, "56001") == 0) + d_56001(); + else if (strcmp(argv[argno] + 2, "6502") == 0) + d_6502(); + else if (strcmp(argv[argno] + 2, "tom") == 0) + d_gpu(); + else if (strcmp(argv[argno] + 2, "jerry") == 0) + d_dsp(); + else + { + printf("Unrecognized CPU '%s'\n", argv[argno] + 2); + errcnt++; + return errcnt; + } + break; case 'o': // Direct object file output case 'O': if (argv[argno][2] != EOS) @@ -350,7 +578,8 @@ int Process(int argc, char ** argv) case 'P': /* * -p .PRG generation w/o symbols - * -ps .PRG generation with symbols + * -ps .PRG generation with symbols + * -px .PRG generation with extended symbols */ switch (argv[argno][2]) { @@ -363,9 +592,14 @@ int Process(int argc, char ** argv) prg_flag = 2; break; + case 'x': + case 'X': + prg_flag = 3; + break; + default: printf("-p: syntax error\n"); - ++errcnt; + errcnt++; return errcnt; } @@ -377,7 +611,7 @@ int Process(int argc, char ** argv) 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; @@ -385,9 +619,9 @@ int Process(int argc, char ** argv) default: segpadsize = 2; break; // Effective autoeven(); } break; - case 's': // Warn about possible short branches + case 's': // Warn about possible short branches and applied optimisations case 'S': - sbra_flag = 1; + optim_warn_flag = 1; break; case 'u': // Make undefined symbols .globl case 'U': @@ -413,17 +647,13 @@ int Process(int argc, char ** argv) if (pagelen < 10) { printf("-y: bad page length\n"); - ++errcnt; + errcnt++; return errcnt; } break; case EOS: // Input is stdin - if (firstfname == NULL) // Kludge first filename - firstfname = defname; - - include(0, "(stdin)"); - Assemble(); + ProcessFile(0, NULL); break; case 'h': // Display command line usage case 'H': @@ -458,10 +688,6 @@ int Process(int argc, char ** argv) } else { - // Record first filename. - if (firstfname == NULL) - firstfname = argv[argno]; - strcpy(fnbuf, argv[argno]); fext(fnbuf, ".s", 0); fd = open(fnbuf, 0); @@ -473,8 +699,7 @@ int Process(int argc, char ** argv) continue; } - include(fd, fnbuf); - Assemble(); + ProcessFile(fd, fnbuf); } } @@ -482,10 +707,13 @@ int Process(int argc, char ** argv) // o save current section (no more code generation) // o do auto-even of all sections (or boundary alignment as requested // through '-r') + // o save the last pc value for 6502 (if we used 6502 at all) and + // detemine if the last section contains anything // o determine name of object file: // - "foo.o" for linkable output; // - "foo.prg" for GEMDOS executable (-p flag). SaveSection(); + int temp_section = cursect; for(i=TEXT; i<=BSS; i<<=1) { @@ -503,12 +731,36 @@ int Process(int argc, char ** argv) SaveSection(); } + SwitchSection(M6502); + + if (sloc != currentorg[0]) + { + currentorg[1] = sloc; + currentorg += 2; + } + + // This looks like an awful kludge... !!! FIX !!! + if (temp_section & (M56001P | M56001X | M56001Y)) + { + SwitchSection(temp_section); + + if (chptr != dsp_currentorg->start) + { + dsp_currentorg->end = chptr; + dsp_currentorg++; + } + } + + SwitchSection(TEXT); + if (objfname == NULL) { if (firstfname == NULL) firstfname = defname; - strcpy(fnbuf, firstfname); + // It's the size of fnbuf minus 5 because of the possible 4 char suffix + // + trailing null (added by fext()). + strncpy(fnbuf, firstfname, sizeof(fnbuf) - 5); fext(fnbuf, (prg_flag ? ".prg" : ".o"), 1); objfname = fnbuf; } @@ -525,7 +777,7 @@ int Process(int argc, char ** argv) if (errcnt == 0) { if ((fd = open(objfname, _OPEN_FLAGS, _PERM_MODE)) < 0) - cantcreat(objfname); + CantCreateFile(objfname); if (verb_flag) { @@ -558,7 +810,6 @@ int Process(int argc, char ** argv) return errcnt; } - // // Determine processor endianess // @@ -573,7 +824,6 @@ int GetEndianess(void) return 1; } - // // Application entry point // @@ -581,25 +831,17 @@ int main(int argc, char ** argv) { 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; + optim_flags[OPT_56K_SHORT] = 1; // This ensures compatibilty with Motorola's 56k assembler 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(); return 0; } -