//
-// RMAC - Reboot's Macro Assembler for all Atari computers
+// RMAC - Renamed Macro Assembler for all Atari computers
// DIRECT.C - Directive Handling
-// Copyright (C) 199x Landon Dyer, 2011-2019 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 DEF_KW
#include "kwtab.h"
-
+#define DEF_REG56
+#define DECL_REG56
+#include "56kregs.h"
+#define DEF_REG68
+#define DECL_REG68
+#include "68kregs.h"
+#define DEF_REGRISC
+#define DECL_REGRISC
+#include "riscregs.h"
TOKEN exprbuf[128]; // Expression buffer
SYM * symbolPtr[1000000]; // Symbol pointers table
int d_comm(void);
int d_dc(WORD);
int d_ds(WORD);
+int d_dsm(WORD);
int d_dcb(WORD);
int d_globl(void);
int d_gpu(void);
int d_opt(void);
int d_dsp(void);
int d_objproc(void);
+int d_align(void);
void SetLargestAlignment(int);
// Directive handler table
d_nofpu, // 65 nofpu
d_opt, // 66 .opt
d_objproc, // 67 .objproc
+ (void *)d_dsm, // 68 .dsm
+ d_align // 69 .align
};
{
uint64_t address;
- if (!rgpu && !rdsp && !robjproc && !m6502 && !dsp56001)
- return error(".org permitted only in GPU/DSP/OP, 56001 and 6502 sections");
+ if (!rgpu && !rdsp && !robjproc && !m6502 && !dsp56001 && !(obj_format == RAW))
+ return error(".org permitted only in GPU/DSP/OP, 56001, 6502 and 68k (with -fr switch) sections");
// M56K can leave the expression off the org for some reason :-/
// (It's because the expression is non-standard, and so we have to look at
switch (tok[0])
{
- case KW_X:
+ case REG56_X:
dsp_currentorg->memtype = ORG_X;
sectionToSwitch = M56001X;
break;
- case KW_Y:
+ case REG56_Y:
dsp_currentorg->memtype = ORG_Y;
sectionToSwitch = M56001Y;
break;
- case KW_P:
+ case REG56_P:
dsp_currentorg->memtype = ORG_P;
sectionToSwitch = M56001P;
break;
- case KW_L:
+ case REG56_L:
dsp_currentorg->memtype = ORG_L;
sectionToSwitch = M56001L;
break;
// N.B.: It seems that by enabling this, even though it works elsewhere, will cause symbols to royally fuck up. Will have to do some digging to figure out why.
// orgactive = 1;
}
+ else
+ {
+ // If we get here we assume it's 68k with RAW output, so this is allowed
+ if (orgactive)
+ {
+ return error("In 68k mode only one .org statement is allowed");
+ }
+
+ org68k_address = address;
+ org68k_active = 1;
+ }
ErrorIfNotAtEOL();
return 0;
formatting = 1;
// "X" & "L" get tokenized now... :-/ Probably should look into preventing this kind of thing from happening (was added with DSP56K code)
- if ((tok[1] != SYMBOL) && (tok[1] != KW_L) && (tok[1] != KW_X))
+ // Note (ggn): This is now much less severe as it's localised for 56k only
+ if ((tok[1] != SYMBOL) && (tok[1] != REG56_L) && (tok[1] != REG56_X))
goto token_err;
- if (tok[1] == KW_L)
+ if (tok[1] == REG56_L)
{
wordlong = 1;
tok += 2;
}
- else if (tok[1] == KW_X)
+ else if (tok[1] == REG56_X)
{
outtype = 0;
tok += 2;
{
// Reset the attributes of this symbol...
regname->sattr = 0;
- regname->sattre &= ~(EQUATEDREG | BANK_0 | BANK_1);
+ regname->sattre &= ~EQUATEDREG;
regname->sattre |= UNDEF_EQUR;
}
//
-// Include binary file
+// Include binary file (can add addition size & position params, comma separated)
//
int d_incbin(void)
{
int fd;
int bytes = 0;
- long pos, size, bytesRead;
+ uint64_t pos, size, bytesRead;
char buf1[256];
int i;
// Attempt to open the include file in the current directory, then (if that
// failed) try list of include files passed in the enviroment string or by
- // the "-d" option.
- if ((fd = open(string[tok[1]], _OPEN_INC)) < 0)
+ // the "-i" option.
+ TOKEN filename = tok[1];
+
+ if ((fd = open(string[filename], _OPEN_INC)) < 0)
{
for(i=0; nthpath("RMACPATH", i, buf1)!=0; i++)
{
if (fd > 0 && buf1[fd - 1] != SLASHCHAR)
strcat(buf1, SLASHSTRING);
- strcat(buf1, string[tok[1]]);
+ strcat(buf1, string[filename]);
if ((fd = open(buf1, _OPEN_INC)) >= 0)
goto allright;
}
- return error("cannot open: \"%s\"", string[tok[1]]);
+ return error("cannot open: \"%s\"", string[filename]);
}
allright:
+ tok += 2;
+
size = lseek(fd, 0L, SEEK_END);
pos = lseek(fd, 0L, SEEK_SET);
+
+ if (*tok != EOL)
+ {
+ // Parse size and position parameters
+ uint64_t requested_size = -1; // -1 means "not set" for these two
+
+ if (*tok++ != ',')
+ {
+ close(fd);
+ return error("expected comma after incbin filename");
+ }
+
+ if (tok != EOL)
+ {
+ if (*tok != ',')
+ {
+ if (abs_expr(&requested_size) != OK)
+ {
+ close(fd);
+ return ERROR;
+ }
+
+ if ((int64_t)requested_size <= 0 || requested_size > size)
+ {
+ close(fd);
+ return error("invalid incbin size requested");
+ }
+ }
+
+ if (*tok != EOL)
+ {
+ if (*tok++ != ',')
+ {
+ close(fd);
+ return error("expected comma after size parameter");
+ }
+
+ if (*tok != EOL)
+ {
+ if (abs_expr(&pos) != OK)
+ {
+ close(fd);
+ return ERROR;
+ }
+
+ if ((int64_t)pos <= 0 || pos > size)
+ {
+ close(fd);
+ return error("invalid incbin position requested");
+ }
+ }
+ }
+
+ if (*tok != EOL)
+ {
+ close(fd);
+ return error("extra characters following incbin");
+ }
+ }
+
+ // Adjust size if the user didn't specify it via the parameter
+ if (requested_size == -1)
+ {
+ requested_size = size - pos;
+ }
+
+ // Are we going to read past the end of the file?
+ if (pos + requested_size > size)
+ {
+ close(fd);
+ return error("invalid combination of incbin position and size");
+ }
+ size = requested_size;
+
+ // All checks passed, let's seek to where the user requested, otherwise at file start
+ lseek(fd, pos, SEEK_SET);
+ }
+
chcheck(size);
- DEBUG { printf("INCBIN: File '%s' is %li bytes.\n", string[tok[1]], size); }
+ DEBUG { printf("INCBIN: File '%s' is %li bytes.\n", string[filename], size); }
char * fileBuffer = (char *)malloc(size);
bytesRead = read(fd, fileBuffer, size);
if (bytesRead != size)
{
- error("was only able to read %li bytes from binary file (%s, %li bytes)", bytesRead, string[tok[1]], size);
+ error("was only able to read %li bytes from binary file (%s, %li bytes)", bytesRead, string[filename], size);
return ERROR;
}
//
int d_regbank0(void)
{
- // Set active register bank zero
- regbank = BANK_0;
+ // Deprecated, it's not as if this did anything useful, ever
+ warn("regbank0 ignored");
return 0;
}
int d_regbank1(void)
{
- // Set active register bank one
- regbank = BANK_1;
+ // Deprecated, it's not as if this did anything useful, ever
+ warn("regbank1 ignored");
return 0;
}
}
+//
+// Adjust location to <alignment> bytes
+//
+int d_align(void)
+{
+ unsigned bytesToSkip;
+ uint64_t eval;
+
+ if (abs_expr(&eval) != OK)
+ return 0;
+
+ if (eval < 2)
+ {
+ return error("Invalid .align value specified");
+ }
+
+ if (dsp56001)
+ {
+ bytesToSkip = eval - sloc % eval;
+ D_ZEROFILL(bytesToSkip*3);
+ return 0;
+ }
+
+ bytesToSkip = eval - (rgpu || rdsp ? orgaddr : sloc) % eval;
+ if ( bytesToSkip != eval )
+ {
+ if ((scattr & SBSS) == 0)
+ {
+ D_ZEROFILL(bytesToSkip);
+ }
+ else
+ {
+ sloc += bytesToSkip;
+
+ if (orgactive)
+ orgaddr += bytesToSkip;
+ }
+ }
+ return 0;
+}
+
+
//
// Do auto-even. This must be called ONLY if 'sloc' is odd.
//
DEBUG { printf("Directive: .ds.[size] = %u, sloc = $%X\n", siz, sloc); }
uint64_t eval;
+ WORD eattr;
if ((cursect & (M6502 | M56KPXYL)) == 0)
{
auto_even();
}
- if (abs_expr(&eval) != OK)
- return 0;
+ if (expr(exprbuf, &eval, &eattr, NULL) < 0)
+ return ERROR;
// Check to see if the value being passed in is negative (who the hell does
// that?--nobody does; it's the code gremlins, or rum, what does it)
- // N.B.: Since 'eval' is of type uint32_t, if it goes negative, it will
+ // N.B.: Since 'eval' is of type uint64_t, if it goes negative, it will
// have its high bit set.
- if (eval & 0x80000000)
+ if (eval & 0x8000000000000000)
return error("negative sizes not allowed in DS");
// In non-TDB section (BSS, ABS and M6502) just advance the location
just_bss = 1; // No data deposited (8-bit CPU mode)
}
- else if (cursect == M56001P || cursect == M56001X || cursect == M56001Y || cursect == M56001L)
+ else if (cursect & M56KPXYL)
{
// Change segment instead of marking blanks.
// Only mark segments we actually wrote something
}
ErrorIfNotAtEOL();
- return 0;
+ return OK;
+}
+
+
+//
+// dsm[.siz] expression
+// Define modulo storage
+// Quoting the Motorola assembler manual:
+// "The DSM directive reserves a block of memory the length of which in words is equal to
+// the value of <expression>.If the runtime location counter is not zero, this directive first
+// advances the runtime location counter to a base address that is a multiple of 2k, where
+// 2k >= <expression>."
+// The kicker of course is written a few sentences after:
+// "<label>, if present, will be assigned the value of the runtime location counter after a valid
+// base address has been established."
+//
+int d_dsm(WORD siz)
+{
+ TOKEN * tok_current = tok; // Keep track of where tok was when we entered this procedure
+ uint64_t eval;
+
+ if (abs_expr(&eval) != OK)
+ return 0;
+
+ // Round up to the next highest power of 2
+ // Nicked from https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
+ eval--;
+ eval |= eval >> 1;
+ eval |= eval >> 2;
+ eval |= eval >> 4;
+ eval |= eval >> 8;
+ eval |= eval >> 16;
+
+ int units_to_skip;
+ units_to_skip = eval + 1 - sloc;
+ sloc += units_to_skip; // Bump up sloc - TODO: check if this goes over the RAM limits?
+
+ // If a label has been defined in the same line as dsm, its value also needs to be adjusted
+ if (label_defined)
+ {
+ SYM * label = lookup(label_defined, LABEL, 0);
+ label->svalue += units_to_skip;
+ }
+
+ tok = tok_current; // Rewind tok back to where it was
+ return d_ds(siz); // And let d_ds take over from here
}
SaveSection();
SwitchSection(TEXT);
activecpu = CPU_68000;
+ regbase = reg68base; // Update register DFA tables
+ regtab = reg68tab;
+ regcheck = reg68check;
+ regaccept = reg68accept;
return 0;
}
//
int d_68881(void)
{
- //d_68000();
activefpu = FPU_68881;
+ regbase = reg68base; // Update register DFA tables
+ regtab = reg68tab;
+ regcheck = reg68check;
+ regaccept = reg68accept;
return 0;
}
//
int d_68882(void)
{
- //d_68000();
activefpu = FPU_68882;
+ regbase = reg68base; // Update register DFA tables
+ regtab = reg68tab;
+ regcheck = reg68check;
+ regaccept = reg68accept;
return 0;
}
if ((obj_format == LOD) || (obj_format == P56))
SwitchSection(M56001P);
+ regbase = reg56base; // Update register DFA tables
+ regtab = reg56tab;
+ regcheck = reg56check;
+ regaccept = reg56accept;
+ used_architectures |= M56001P | M56001X | M56001Y | M56001L;
return 0;
}
rdsp = 0; // Unset DSP assembly
robjproc = 0; // Unset OP assembly
dsp56001 = 0; // Unset 56001 assembly
- regbank = BANK_N; // Set no default register bank
+
+ regbase = regriscbase; // Update register DFA tables
+ regtab = regrisctab;
+ regcheck = regrisccheck;
+ regaccept = regriscaccept;
+ //used_architectures |= MGPU; // TODO: Should GPU/DSP have their own dedicated sections in the long run?
return 0;
}
rgpu = 0; // Unset GPU assembly
robjproc = 0; // Unset OP assembly
dsp56001 = 0; // Unset 56001 assembly
- regbank = BANK_N; // Set no default register bank
+
+ regbase = regriscbase; // Update register DFA tables
+ regtab = regrisctab;
+ regcheck = regrisccheck;
+ regaccept = regriscaccept;
+ //used_architectures |= MDSP; // TODO: Should GPU/DSP have their own dedicated sections in the long run?
return 0;
}
eval += 2;
}
- else if (*tok >= KW_D0 && *tok <= KW_A7)
+ else if (*tok >= REG68_D0 && *tok <= REG68_A7)
{
if (reglist(&rlist) < 0)
return 0;
{
switch ((int)*tok)
{
- case KW_USP:
- case KW_SSP:
- case KW_PC:
+ case REG68_USP:
+ case REG68_SSP:
+ case REG68_PC:
eval += 2;
// FALLTHROUGH
- case KW_SR:
- case KW_CCR:
+ case REG68_SR:
+ case REG68_CCR:
eval += 2;
tok++;
break;
tok++;
}
- else if (*tok >= KW_D0 && *tok <= KW_A7)
+ else if (*tok >= REG68_D0 && *tok <= REG68_A7)
{
if (reglist(&rlist) < 0)
return 0;
{
switch ((int)*tok)
{
- case KW_USP:
- case KW_SSP:
- case KW_PC:
+ case REG68_USP:
+ case REG68_SSP:
+ case REG68_PC:
eval += 2;
// FALLTHROUGH
- case KW_SR:
- case KW_CCR:
+ case REG68_SR:
+ case REG68_CCR:
eval += 2;
tok++;
break;
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;
}