Merge branch 'master' into ca65_jmp_abs_wrap_error
This commit is contained in:
@@ -115,7 +115,11 @@ install:
|
||||
$(INSTALL) ../bin/* $(DESTDIR)$(bindir)
|
||||
|
||||
avail:
|
||||
ifneq ($(patsubst %,../bin/%,$(PROGS)),$(wildcard $(patsubst %,../bin/%,$(PROGS))))
|
||||
$(error executables are missing, please run make first)
|
||||
else
|
||||
$(foreach prog,$(PROGS),$(AVAIL_recipe))
|
||||
endif
|
||||
|
||||
unavail:
|
||||
$(foreach prog,$(PROGS),$(UNAVAIL_recipe))
|
||||
|
||||
@@ -43,6 +43,10 @@
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
/* EffAddr Flags */
|
||||
#define EFFADDR_OVERRIDE_ZP 0x00000001UL
|
||||
|
||||
|
||||
|
||||
/* GetEA result struct */
|
||||
typedef struct EffAddr EffAddr;
|
||||
@@ -51,6 +55,7 @@ struct EffAddr {
|
||||
unsigned long AddrModeSet; /* Possible addressing modes */
|
||||
struct ExprNode* Expr; /* Expression if any (NULL otherwise) */
|
||||
unsigned Reg; /* Register number in sweet16 mode */
|
||||
unsigned long Flags; /* Other properties */
|
||||
|
||||
/* The following fields are used inside instr.c */
|
||||
unsigned AddrMode; /* Actual addressing mode used */
|
||||
|
||||
@@ -72,11 +72,13 @@ void GetEA (EffAddr* A)
|
||||
/* Clear the output struct */
|
||||
A->AddrModeSet = 0;
|
||||
A->Expr = 0;
|
||||
A->Flags = 0;
|
||||
|
||||
/* Handle an addressing size override */
|
||||
switch (CurTok.Tok) {
|
||||
case TOK_OVERRIDE_ZP:
|
||||
Restrictions = AM65_DIR | AM65_DIR_X | AM65_DIR_Y;
|
||||
A->Flags |= EFFADDR_OVERRIDE_ZP;
|
||||
NextTok ();
|
||||
break;
|
||||
|
||||
|
||||
@@ -66,6 +66,7 @@ static const char* const FeatureKeys[FEAT_COUNT] = {
|
||||
"addrsize",
|
||||
"bracket_as_indirect",
|
||||
"string_escapes",
|
||||
"long_jsr_jmp_rts",
|
||||
};
|
||||
|
||||
|
||||
@@ -97,37 +98,30 @@ feature_t FindFeature (const StrBuf* Key)
|
||||
|
||||
|
||||
|
||||
feature_t SetFeature (const StrBuf* Key)
|
||||
/* Find the feature and set the corresponding flag if the feature is known.
|
||||
** In any case, return the feature found. An invalid Key will return
|
||||
** FEAT_UNKNOWN.
|
||||
void SetFeature (feature_t Feature, unsigned char On)
|
||||
/* Set the corresponding feature flag if Feature is valid.
|
||||
*/
|
||||
{
|
||||
/* Map the string to an enum value */
|
||||
feature_t Feature = FindFeature (Key);
|
||||
|
||||
/* Set the flags */
|
||||
switch (Feature) {
|
||||
case FEAT_DOLLAR_IS_PC: DollarIsPC = 1; break;
|
||||
case FEAT_LABELS_WITHOUT_COLONS: NoColonLabels = 1; break;
|
||||
case FEAT_LOOSE_STRING_TERM: LooseStringTerm = 1; break;
|
||||
case FEAT_LOOSE_CHAR_TERM: LooseCharTerm = 1; break;
|
||||
case FEAT_AT_IN_IDENTIFIERS: AtInIdents = 1; break;
|
||||
case FEAT_DOLLAR_IN_IDENTIFIERS: DollarInIdents = 1; break;
|
||||
case FEAT_LEADING_DOT_IN_IDENTIFIERS: LeadingDotInIdents= 1; break;
|
||||
case FEAT_ORG_PER_SEG: OrgPerSeg = 1; break;
|
||||
case FEAT_PC_ASSIGNMENT: PCAssignment = 1; break;
|
||||
case FEAT_MISSING_CHAR_TERM: MissingCharTerm = 1; break;
|
||||
case FEAT_UBIQUITOUS_IDENTS: UbiquitousIdents = 1; break;
|
||||
case FEAT_C_COMMENTS: CComments = 1; break;
|
||||
case FEAT_FORCE_RANGE: ForceRange = 1; break;
|
||||
case FEAT_UNDERLINE_IN_NUMBERS: UnderlineInNumbers= 1; break;
|
||||
case FEAT_ADDRSIZE: AddrSize = 1; break;
|
||||
case FEAT_BRACKET_AS_INDIRECT: BracketAsIndirect = 1; break;
|
||||
case FEAT_STRING_ESCAPES: StringEscapes = 1; break;
|
||||
default: /* Keep gcc silent */ break;
|
||||
case FEAT_DOLLAR_IS_PC: DollarIsPC = On; break;
|
||||
case FEAT_LABELS_WITHOUT_COLONS: NoColonLabels = On; break;
|
||||
case FEAT_LOOSE_STRING_TERM: LooseStringTerm = On; break;
|
||||
case FEAT_LOOSE_CHAR_TERM: LooseCharTerm = On; break;
|
||||
case FEAT_AT_IN_IDENTIFIERS: AtInIdents = On; break;
|
||||
case FEAT_DOLLAR_IN_IDENTIFIERS: DollarInIdents = On; break;
|
||||
case FEAT_LEADING_DOT_IN_IDENTIFIERS: LeadingDotInIdents= On; break;
|
||||
case FEAT_ORG_PER_SEG: OrgPerSeg = On; break;
|
||||
case FEAT_PC_ASSIGNMENT: PCAssignment = On; break;
|
||||
case FEAT_MISSING_CHAR_TERM: MissingCharTerm = On; break;
|
||||
case FEAT_UBIQUITOUS_IDENTS: UbiquitousIdents = On; break;
|
||||
case FEAT_C_COMMENTS: CComments = On; break;
|
||||
case FEAT_FORCE_RANGE: ForceRange = On; break;
|
||||
case FEAT_UNDERLINE_IN_NUMBERS: UnderlineInNumbers= On; break;
|
||||
case FEAT_ADDRSIZE: AddrSize = On; break;
|
||||
case FEAT_BRACKET_AS_INDIRECT: BracketAsIndirect = On; break;
|
||||
case FEAT_STRING_ESCAPES: StringEscapes = On; break;
|
||||
case FEAT_LONG_JSR_JMP_RTS: LongJsrJmpRts = On; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
/* Return the value found */
|
||||
return Feature;
|
||||
}
|
||||
|
||||
@@ -68,6 +68,7 @@ typedef enum {
|
||||
FEAT_ADDRSIZE,
|
||||
FEAT_BRACKET_AS_INDIRECT,
|
||||
FEAT_STRING_ESCAPES,
|
||||
FEAT_LONG_JSR_JMP_RTS,
|
||||
|
||||
/* Special value: Number of features available */
|
||||
FEAT_COUNT
|
||||
@@ -86,10 +87,8 @@ feature_t FindFeature (const StrBuf* Key);
|
||||
** feature is invalid, return FEAT_UNKNOWN.
|
||||
*/
|
||||
|
||||
feature_t SetFeature (const StrBuf* Key);
|
||||
/* Find the feature and set the corresponding flag if the feature is known.
|
||||
** In any case, return the feature found. An invalid Key will return
|
||||
** FEAT_UNKNOWN.
|
||||
void SetFeature (feature_t Feature, unsigned char On);
|
||||
/* Set the corresponding feature flag if Feature is valid.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -67,6 +67,7 @@ unsigned char LineCont = 0; /* Allow line continuation */
|
||||
unsigned char LargeAlignment = 0; /* Don't warn about large alignments */
|
||||
unsigned char RelaxChecks = 0; /* Relax a few assembler checks */
|
||||
unsigned char StringEscapes = 0; /* Allow C-style escapes in strings */
|
||||
unsigned char LongJsrJmpRts = 0; /* Allow JSR/JMP/RTS as alias for JSL/JML/RTL */
|
||||
unsigned char WarningsAsErrors = 0; /* Error if any warnings */
|
||||
|
||||
/* Emulation features */
|
||||
|
||||
@@ -69,6 +69,7 @@ extern unsigned char LineCont; /* Allow line continuation */
|
||||
extern unsigned char LargeAlignment; /* Don't warn about large alignments */
|
||||
extern unsigned char RelaxChecks; /* Relax a few assembler checks */
|
||||
extern unsigned char StringEscapes; /* Allow C-style escapes in strings */
|
||||
extern unsigned char LongJsrJmpRts; /* Allow JSR/JMP/RTS as alias for JSL/JML/RTL */
|
||||
extern unsigned char WarningsAsErrors; /* Error if any warnings */
|
||||
|
||||
/* Emulation features */
|
||||
|
||||
@@ -75,7 +75,7 @@ void FinishIncludePaths (void)
|
||||
AddSubSearchPathFromEnv (IncSearchPath, "CC65_HOME", "asminc");
|
||||
|
||||
/* Add some compiled-in search paths if defined at compile time. */
|
||||
#if defined(CA65_INC) && !defined(_WIN32)
|
||||
#if defined(CA65_INC) && !defined(_WIN32) && !defined(_AMIGA)
|
||||
AddSearchPath (IncSearchPath, CA65_INC);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -120,9 +120,21 @@ static void PutJMP (const InsDesc* Ins);
|
||||
** to check for this case and is otherwise identical to PutAll.
|
||||
*/
|
||||
|
||||
static void PutJMP816 (const InsDesc* Ins);
|
||||
/* Handle the JMP instruction for the 816.
|
||||
** Allowing the long_jsr_jmp_rts feature to permit a long JMP.
|
||||
** Note that JMP [abs] and JML [abs] are always both permitted for instruction $DC,
|
||||
** because the [] notation for long indirection makes the generated instruction unambiguous.
|
||||
*/
|
||||
|
||||
static void PutJSR816 (const InsDesc* Ins);
|
||||
/* Handle the JSR instruction for the 816.
|
||||
** Allowing the long_jsr_jmp_rts feature to permit a long JSR.
|
||||
*/
|
||||
|
||||
static void PutRTS (const InsDesc* Ins attribute ((unused)));
|
||||
/* Handle the RTS instruction for the 816. In smart mode emit a RTL opcode if
|
||||
** the enclosing scope is FAR.
|
||||
** the enclosing scope is FAR, but only if the long_jsr_jmp_rts feature applies.
|
||||
*/
|
||||
|
||||
static void PutAll (const InsDesc* Ins);
|
||||
@@ -169,7 +181,7 @@ static const struct {
|
||||
{ "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
|
||||
{ "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
|
||||
{ "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
|
||||
{ "BRK", 0x0000001, 0x00, 0, PutAll },
|
||||
{ "BRK", 0x0800005, 0x00, 6, PutAll },
|
||||
{ "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
|
||||
{ "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
|
||||
{ "CLC", 0x0000001, 0x18, 0, PutAll },
|
||||
@@ -240,7 +252,7 @@ static const struct {
|
||||
{ "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
|
||||
{ "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
|
||||
{ "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
|
||||
{ "BRK", 0x0000001, 0x00, 0, PutAll },
|
||||
{ "BRK", 0x0800005, 0x00, 6, PutAll },
|
||||
{ "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
|
||||
{ "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
|
||||
{ "CLC", 0x0000001, 0x18, 0, PutAll },
|
||||
@@ -330,7 +342,7 @@ static const struct {
|
||||
{ "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
|
||||
{ "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
|
||||
{ "BRA", 0x0020000, 0x12, 0, PutPCRel8 }, /* DTV */
|
||||
{ "BRK", 0x0000001, 0x00, 0, PutAll },
|
||||
{ "BRK", 0x0800005, 0x00, 6, PutAll },
|
||||
{ "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
|
||||
{ "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
|
||||
{ "CLC", 0x0000001, 0x18, 0, PutAll },
|
||||
@@ -406,7 +418,7 @@ static const struct {
|
||||
{ "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
|
||||
{ "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
|
||||
{ "BRA", 0x0020000, 0x80, 0, PutPCRel8 },
|
||||
{ "BRK", 0x0000001, 0x00, 0, PutAll },
|
||||
{ "BRK", 0x0800005, 0x00, 6, PutAll },
|
||||
{ "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
|
||||
{ "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
|
||||
{ "CLC", 0x0000001, 0x18, 0, PutAll },
|
||||
@@ -498,7 +510,7 @@ static const struct {
|
||||
{ "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
|
||||
{ "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
|
||||
{ "BRA", 0x0020000, 0x80, 0, PutPCRel8 },
|
||||
{ "BRK", 0x0000001, 0x00, 0, PutAll },
|
||||
{ "BRK", 0x0800005, 0x00, 6, PutAll },
|
||||
{ "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
|
||||
{ "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
|
||||
{ "CLC", 0x0000001, 0x18, 0, PutAll },
|
||||
@@ -610,7 +622,7 @@ static const struct {
|
||||
{ "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
|
||||
{ "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
|
||||
{ "BRA", 0x0020000, 0x80, 0, PutPCRel8 },
|
||||
{ "BRK", 0x0000001, 0x00, 0, PutAll },
|
||||
{ "BRK", 0x0800005, 0x00, 6, PutAll },
|
||||
{ "BSR", 0x0040000, 0x63, 0, PutPCRel4510 },
|
||||
{ "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
|
||||
{ "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
|
||||
@@ -735,7 +747,7 @@ static const struct {
|
||||
{ "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
|
||||
{ "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
|
||||
{ "BRA", 0x0020000, 0x80, 0, PutPCRel8 },
|
||||
{ "BRK", 0x0000005, 0x00, 6, PutAll },
|
||||
{ "BRK", 0x0800005, 0x00, 6, PutAll },
|
||||
{ "BRL", 0x0040000, 0x82, 0, PutPCRel16 },
|
||||
{ "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
|
||||
{ "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
|
||||
@@ -744,7 +756,7 @@ static const struct {
|
||||
{ "CLI", 0x0000001, 0x58, 0, PutAll },
|
||||
{ "CLV", 0x0000001, 0xb8, 0, PutAll },
|
||||
{ "CMP", 0x0b8f6fc, 0xc0, 0, PutAll },
|
||||
{ "COP", 0x0000004, 0x02, 6, PutAll },
|
||||
{ "COP", 0x0800005, 0x02, 6, PutAll },
|
||||
{ "CPA", 0x0b8f6fc, 0xc0, 0, PutAll }, /* == CMP */
|
||||
{ "CPX", 0x0c0000c, 0xe0, 1, PutAll },
|
||||
{ "CPY", 0x0c0000c, 0xc0, 1, PutAll },
|
||||
@@ -758,9 +770,9 @@ static const struct {
|
||||
{ "INX", 0x0000001, 0xe8, 0, PutAll },
|
||||
{ "INY", 0x0000001, 0xc8, 0, PutAll },
|
||||
{ "JML", 0x4000010, 0x5c, 1, PutAll },
|
||||
{ "JMP", 0x4010818, 0x4c, 6, PutAll },
|
||||
{ "JMP", 0x4010818, 0x4c, 6, PutJMP816 },
|
||||
{ "JSL", 0x0000010, 0x20, 7, PutAll },
|
||||
{ "JSR", 0x0010018, 0x20, 7, PutAll },
|
||||
{ "JSR", 0x0010018, 0x20, 7, PutJSR816 },
|
||||
{ "LDA", 0x0b8f6fc, 0xa0, 0, PutAll },
|
||||
{ "LDX", 0x0c0030c, 0xa2, 1, PutAll },
|
||||
{ "LDY", 0x0c0006c, 0xa0, 1, PutAll },
|
||||
@@ -821,7 +833,7 @@ static const struct {
|
||||
{ "TYA", 0x0000001, 0x98, 0, PutAll },
|
||||
{ "TYX", 0x0000001, 0xbb, 0, PutAll },
|
||||
{ "WAI", 0x0000001, 0xcb, 0, PutAll },
|
||||
{ "WDM", 0x0000004, 0x42, 6, PutAll },
|
||||
{ "WDM", 0x0800004, 0x42, 6, PutAll },
|
||||
{ "XBA", 0x0000001, 0xeb, 0, PutAll },
|
||||
{ "XCE", 0x0000001, 0xfb, 0, PutAll }
|
||||
}
|
||||
@@ -897,7 +909,7 @@ static const struct {
|
||||
{ "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
|
||||
{ "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
|
||||
{ "BRA", 0x0020000, 0x80, 0, PutPCRel8 },
|
||||
{ "BRK", 0x0000001, 0x00, 0, PutAll },
|
||||
{ "BRK", 0x0800005, 0x00, 6, PutAll },
|
||||
{ "BSR", 0x0020000, 0x44, 0, PutPCRel8 },
|
||||
{ "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
|
||||
{ "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
|
||||
@@ -1257,7 +1269,8 @@ static int EvalEA (const InsDesc* Ins, EffAddr* A)
|
||||
ExprNode* Left = A->Expr->Left;
|
||||
if ((A->Expr->Op == EXPR_BYTE0 || A->Expr->Op == EXPR_BYTE1) &&
|
||||
Left->Op == EXPR_SYMBOL &&
|
||||
GetSymAddrSize (Left->V.Sym) != ADDR_SIZE_ZP) {
|
||||
GetSymAddrSize (Left->V.Sym) != ADDR_SIZE_ZP &&
|
||||
!(A->Flags & EFFADDR_OVERRIDE_ZP)) {
|
||||
|
||||
/* Output a warning */
|
||||
Warning (1, "Suspicious address expression");
|
||||
@@ -1605,7 +1618,7 @@ static void PutJMP (const InsDesc* Ins)
|
||||
if (EvalEA (Ins, &A)) {
|
||||
|
||||
/* Check for indirect addressing */
|
||||
if (A.AddrModeBit & AM65_ABS_IND && CPU < CPU_65SC02) {
|
||||
if ((A.AddrModeBit & AM65_ABS_IND) && (CPU < CPU_65SC02)) {
|
||||
|
||||
/* Compare the low byte of the expression to 0xFF to check for
|
||||
** a page cross. Be sure to use a copy of the expression otherwise
|
||||
@@ -1628,12 +1641,46 @@ static void PutJMP (const InsDesc* Ins)
|
||||
|
||||
|
||||
|
||||
static void PutRTS (const InsDesc* Ins attribute ((unused)))
|
||||
/* Handle the RTS instruction for the 816. In smart mode emit a RTL opcode if
|
||||
** the enclosing scope is FAR.
|
||||
static void PutJMP816 (const InsDesc* Ins)
|
||||
/* Handle the JMP instruction for the 816.
|
||||
** Allowing the long_jsr_jmp_rts feature to permit a long JMP.
|
||||
** Note that JMP [abs] and JML [abs] are always both permitted for instruction $DC,
|
||||
** because the [] notation for long indirection makes the generated instruction unambiguous.
|
||||
*/
|
||||
{
|
||||
if (SmartMode && CurrentScope->AddrSize == ADDR_SIZE_FAR) {
|
||||
if (LongJsrJmpRts) {
|
||||
PutJMP (Ins);
|
||||
} else {
|
||||
InsDesc InsAbs = *Ins;
|
||||
InsAbs.AddrMode &= ~(AM65_ABS_LONG);
|
||||
PutJMP (&InsAbs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void PutJSR816 (const InsDesc* Ins)
|
||||
/* Handle the JSR instruction for the 816.
|
||||
** Allowing the long_jsr_jmp_rts feature to permit a long JSR.
|
||||
*/
|
||||
{
|
||||
if (LongJsrJmpRts) {
|
||||
PutAll (Ins);
|
||||
} else {
|
||||
InsDesc InsAbs = *Ins;
|
||||
InsAbs.AddrMode &= ~(AM65_ABS_LONG);
|
||||
PutJMP (&InsAbs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void PutRTS (const InsDesc* Ins attribute ((unused)))
|
||||
/* Handle the RTS instruction for the 816. In smart mode emit a RTL opcode if
|
||||
** the enclosing scope is FAR, but only if the long_jsr_jmp_rts feature applies.
|
||||
*/
|
||||
{
|
||||
if (LongJsrJmpRts && SmartMode && CurrentScope->AddrSize == ADDR_SIZE_FAR) {
|
||||
Emit0 (0x6B); /* RTL */
|
||||
} else {
|
||||
Emit0 (0x60); /* RTS */
|
||||
|
||||
@@ -390,7 +390,20 @@ void MacDef (unsigned Style)
|
||||
{
|
||||
Macro* M;
|
||||
TokNode* N;
|
||||
FilePos Pos;
|
||||
int HaveParams;
|
||||
int LastTokWasSep;
|
||||
|
||||
/* For classic macros, remember if we are at the beginning of the line.
|
||||
** If the macro name and parameters pass our checks then we will be on a
|
||||
** new line, so set it now
|
||||
*/
|
||||
LastTokWasSep = 1;
|
||||
|
||||
/* Save the position of the start of the macro definition to allow
|
||||
** using Perror to display the error if .endmacro isn't found
|
||||
*/
|
||||
Pos = CurTok.Pos;
|
||||
|
||||
/* We expect a macro name here */
|
||||
if (CurTok.Tok != TOK_IDENT) {
|
||||
@@ -491,14 +504,16 @@ void MacDef (unsigned Style)
|
||||
while (1) {
|
||||
/* Check for end of macro */
|
||||
if (Style == MAC_STYLE_CLASSIC) {
|
||||
/* In classic macros, only .endmacro is allowed */
|
||||
if (CurTok.Tok == TOK_ENDMACRO) {
|
||||
/* In classic macros, if .endmacro is not at the start of the line
|
||||
** it will be added to the macro definition instead of closing it.
|
||||
*/
|
||||
if (CurTok.Tok == TOK_ENDMACRO && LastTokWasSep) {
|
||||
/* Done */
|
||||
break;
|
||||
}
|
||||
/* May not have end of file in a macro definition */
|
||||
if (CurTok.Tok == TOK_EOF) {
|
||||
Error ("'.ENDMACRO' expected");
|
||||
PError (&Pos, "'.ENDMACRO' expected for macro '%m%p'", &M->Name);
|
||||
goto Done;
|
||||
}
|
||||
} else {
|
||||
@@ -573,6 +588,11 @@ void MacDef (unsigned Style)
|
||||
}
|
||||
++M->TokCount;
|
||||
|
||||
/* Save if last token was a separator to know if .endmacro is at
|
||||
** the start of a line
|
||||
*/
|
||||
LastTokWasSep = TokIsSep(CurTok.Tok);
|
||||
|
||||
/* Read the next token */
|
||||
NextTok ();
|
||||
}
|
||||
|
||||
@@ -489,12 +489,15 @@ static void OptDebugInfo (const char* Opt attribute ((unused)),
|
||||
static void OptFeature (const char* Opt attribute ((unused)), const char* Arg)
|
||||
/* Set an emulation feature */
|
||||
{
|
||||
/* Make a string buffer from Arg */
|
||||
StrBuf Feature;
|
||||
/* Make a string buffer from Arg and use it to find the feature. */
|
||||
StrBuf StrFeature;
|
||||
feature_t Feature = FindFeature (SB_InitFromString (&StrFeature, Arg));
|
||||
|
||||
/* Set the feature, check for errors */
|
||||
if (SetFeature (SB_InitFromString (&Feature, Arg)) == FEAT_UNKNOWN) {
|
||||
/* Enable the feature, check for errors */
|
||||
if (Feature == FEAT_UNKNOWN) {
|
||||
AbEnd ("Illegal emulation feature: '%s'", Arg);
|
||||
} else {
|
||||
SetFeature (Feature, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -855,7 +858,12 @@ static void OneLine (void)
|
||||
/* The line has switched the segment */
|
||||
Size = 0;
|
||||
}
|
||||
DefSizeOfSymbol (Sym, Size);
|
||||
/* Suppress .size Symbol if this Symbol already has a multiply-defined error,
|
||||
** as it will only create its own additional unnecessary error.
|
||||
*/
|
||||
if ((Sym->Flags & SF_MULTDEF) == 0) {
|
||||
DefSizeOfSymbol (Sym, Size);
|
||||
}
|
||||
}
|
||||
|
||||
/* Line separator must come here */
|
||||
|
||||
@@ -1023,7 +1023,10 @@ static void DoFatal (void)
|
||||
static void DoFeature (void)
|
||||
/* Switch the Feature option */
|
||||
{
|
||||
/* Allow a list of comma separated keywords */
|
||||
feature_t Feature;
|
||||
unsigned char On;
|
||||
|
||||
/* Allow a list of comma separated feature keywords with optional +/- or ON/OFF */
|
||||
while (1) {
|
||||
|
||||
/* We expect an identifier */
|
||||
@@ -1034,18 +1037,24 @@ static void DoFeature (void)
|
||||
|
||||
/* Make the string attribute lower case */
|
||||
LocaseSVal ();
|
||||
|
||||
/* Set the feature and check for errors */
|
||||
if (SetFeature (&CurTok.SVal) == FEAT_UNKNOWN) {
|
||||
Feature = FindFeature(&CurTok.SVal);
|
||||
if (Feature == FEAT_UNKNOWN) {
|
||||
/* Not found */
|
||||
ErrorSkip ("Invalid feature: '%m%p'", &CurTok.SVal);
|
||||
return;
|
||||
} else {
|
||||
/* Skip the keyword */
|
||||
NextTok ();
|
||||
}
|
||||
NextTok ();
|
||||
|
||||
/* Optional +/- or ON/OFF */
|
||||
On = 1;
|
||||
if (CurTok.Tok != TOK_COMMA && !TokIsSep (CurTok.Tok)) {
|
||||
SetBoolOption(&On);
|
||||
}
|
||||
|
||||
/* Allow more than one keyword */
|
||||
/* Apply feature setting. */
|
||||
SetFeature (Feature, On);
|
||||
|
||||
/* Allow more than one feature separated by commas. */
|
||||
if (CurTok.Tok == TOK_COMMA) {
|
||||
NextTok ();
|
||||
} else {
|
||||
|
||||
@@ -112,6 +112,7 @@ struct CharSource {
|
||||
CharSource* Next; /* Linked list of char sources */
|
||||
token_t Tok; /* Last token */
|
||||
int C; /* Last character */
|
||||
int SkipN; /* For '\r\n' line endings, skip '\n\ if next */
|
||||
const CharSourceFunctions* Func; /* Pointer to function table */
|
||||
union {
|
||||
InputFile File; /* File data */
|
||||
@@ -325,6 +326,7 @@ static void UseCharSource (CharSource* S)
|
||||
Source = S;
|
||||
|
||||
/* Read the first character from the new file */
|
||||
S->SkipN = 0;
|
||||
S->Func->NextChar (S);
|
||||
|
||||
/* Setup the next token so it will be skipped on the next call to
|
||||
@@ -386,6 +388,11 @@ static void IFNextChar (CharSource* S)
|
||||
while (1) {
|
||||
|
||||
int N = fgetc (S->V.File.F);
|
||||
if (N == '\n' && S->SkipN) {
|
||||
N = fgetc (S->V.File.F);
|
||||
}
|
||||
S->SkipN = 0;
|
||||
|
||||
if (N == EOF) {
|
||||
/* End of file. Accept files without a newline at the end */
|
||||
if (SB_NotEmpty (&S->V.File.Line)) {
|
||||
@@ -401,9 +408,12 @@ static void IFNextChar (CharSource* S)
|
||||
|
||||
/* Check for end of line */
|
||||
} else if (N == '\n') {
|
||||
|
||||
/* End of line */
|
||||
break;
|
||||
} else if (N == '\r') {
|
||||
/* End of line, skip '\n' if it's the next character */
|
||||
S->SkipN = 1;
|
||||
break;
|
||||
|
||||
/* Collect other stuff */
|
||||
} else {
|
||||
|
||||
@@ -306,7 +306,7 @@ void SegAlign (unsigned long Alignment, int FillVal)
|
||||
ActiveSeg->Align = CombinedAlignment;
|
||||
|
||||
/* Output a warning for larger alignments if not suppressed */
|
||||
if (CombinedAlignment >= LARGE_ALIGNMENT && !LargeAlignment) {
|
||||
if (CombinedAlignment >= LARGE_ALIGNMENT && CombinedAlignment > ActiveSeg->Align && CombinedAlignment > Alignment && !LargeAlignment) {
|
||||
Warning (0, "Combined alignment is suspiciously large (%lu)",
|
||||
CombinedAlignment);
|
||||
}
|
||||
|
||||
@@ -570,7 +570,18 @@ void SymCheck (void)
|
||||
|
||||
/* Check for open scopes */
|
||||
if (CurrentScope->Parent != 0) {
|
||||
Error ("Local scope was not closed");
|
||||
if (CurrentScope->Label) {
|
||||
/* proc has a label indicating the line it was opened. */
|
||||
LIError (&CurrentScope->Label->DefLines,
|
||||
"Local proc '%s' was not closed",
|
||||
GetString (CurrentScope->Name));
|
||||
} else {
|
||||
/* scope has no label to track a line number, uses end-of-document line instead.
|
||||
** Anonymous scopes will reveal their internal automatic name.
|
||||
*/
|
||||
Error ("Local scope '%s' was not closed",
|
||||
GetString (CurrentScope->Name));
|
||||
}
|
||||
}
|
||||
|
||||
/* First pass: Walk through all symbols, checking for undefined's and
|
||||
|
||||
@@ -1153,6 +1153,8 @@ static unsigned Opt_a_toscmpbool (StackOpData* D, const char* BoolTransformer)
|
||||
|
||||
/* Save lhs into zeropage */
|
||||
AddStoreLhsA (D);
|
||||
/* AddStoreLhsA may have moved the OpIndex, recalculate insertion point to prevent label migration. */
|
||||
D->IP = D->OpIndex + 1;
|
||||
|
||||
/* cmp */
|
||||
X = NewCodeEntry (OP65_CMP, AM65_ZP, D->ZPLo, 0, D->OpEntry->LI);
|
||||
@@ -1206,6 +1208,8 @@ static unsigned Opt_a_tosicmp (StackOpData* D)
|
||||
/* RHS src is not directly comparable */
|
||||
X = NewCodeEntry (OP65_STA, AM65_ZP, D->ZPHi, 0, D->OpEntry->LI);
|
||||
InsertEntry (D, X, D->Rhs.A.ChgIndex + 1);
|
||||
/* RHS insertion may have moved the OpIndex, recalculate insertion point to prevent label migration. */
|
||||
D->IP = D->OpIndex + 1;
|
||||
|
||||
/* Cmp with stored RHS */
|
||||
X = NewCodeEntry (OP65_CMP, AM65_ZP, D->ZPHi, 0, D->OpEntry->LI);
|
||||
|
||||
@@ -803,7 +803,6 @@ const Type* GetStructReplacementType (const Type* SType)
|
||||
switch (SizeOf (SType)) {
|
||||
case 1: NewType = type_uchar; break;
|
||||
case 2: NewType = type_uint; break;
|
||||
case 3: /* FALLTHROUGH */
|
||||
case 4: NewType = type_ulong; break;
|
||||
default: NewType = SType; break;
|
||||
}
|
||||
|
||||
@@ -3090,9 +3090,10 @@ static void parseadd (ExprDesc* Expr, int DoArrayRef)
|
||||
Expr->Type = Expr2.Type;
|
||||
} else if (!DoArrayRef && IsClassInt (lhst) && IsClassInt (rhst)) {
|
||||
/* Integer addition */
|
||||
flags = typeadjust (Expr, &Expr2, 0);
|
||||
/* Load rhs into the primary */
|
||||
LoadExpr (CF_NONE, &Expr2);
|
||||
/* Adjust rhs primary if needed */
|
||||
flags = typeadjust (Expr, &Expr2, 0);
|
||||
} else {
|
||||
/* OOPS */
|
||||
AddDone = -1;
|
||||
|
||||
@@ -601,7 +601,7 @@ void NewFunc (SymEntry* Func, FuncDesc* D)
|
||||
** We don't currently support this case.
|
||||
*/
|
||||
if (RType == Param->Type) {
|
||||
Error ("Passing '%s' of this size by value is not supported", GetFullTypeName (Param->Type));
|
||||
Error ("Passing '%s' of this size (%d) by value is not supported", GetFullTypeName (Param->Type), SizeOf (RType));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ void FinishIncludePaths (void)
|
||||
AddSubSearchPathFromEnv (SysIncSearchPath, "CC65_HOME", "include");
|
||||
|
||||
/* Add some compiled-in search paths if defined at compile time. */
|
||||
#if defined(CC65_INC) && !defined(_WIN32)
|
||||
#if defined(CC65_INC) && !defined(_WIN32) && !defined(_AMIGA)
|
||||
AddSearchPath (SysIncSearchPath, CC65_INC);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1216,7 +1216,7 @@ static void OptPrintTargetPath (const char* Opt attribute ((unused)),
|
||||
|
||||
SearchPaths* TargetPaths = NewSearchPath ();
|
||||
AddSubSearchPathFromEnv (TargetPaths, "CC65_HOME", "target");
|
||||
#if defined(CL65_TGT) && !defined(_WIN32)
|
||||
#if defined(CL65_TGT) && !defined(_WIN32) && !defined(_AMIGA)
|
||||
AddSearchPath (TargetPaths, CL65_TGT);
|
||||
#endif
|
||||
AddSubSearchPathFromBin (TargetPaths, "target");
|
||||
|
||||
@@ -193,8 +193,16 @@ static void BinWriteMem (BinDesc* D, MemoryArea* M)
|
||||
NewAddr += M->Start;
|
||||
}
|
||||
if (DoWrite || (M->Flags & MF_FILL) != 0) {
|
||||
/* Seek in "overwrite" segments */
|
||||
if (S->Flags & SF_OVERWRITE) {
|
||||
/* Seek in "overwrite" segments. Fill if the seek position has not been reached yet. */
|
||||
unsigned long FileLength;
|
||||
unsigned long SeekTarget = NewAddr - M->Start + M->FileOffs;
|
||||
fseek (D->F, 0, SEEK_END);
|
||||
FileLength = ftell (D->F);
|
||||
if (SeekTarget > FileLength) {
|
||||
WriteMult (D->F, M->FillVal, SeekTarget - FileLength);
|
||||
PrintNumVal ("SF_OVERWRITE", SeekTarget - FileLength);
|
||||
}
|
||||
fseek (D->F, NewAddr - M->Start + M->FileOffs, SEEK_SET);
|
||||
} else {
|
||||
WriteMult (D->F, M->FillVal, NewAddr-Addr);
|
||||
|
||||
@@ -1950,6 +1950,10 @@ unsigned CfgProcess (void)
|
||||
/* Remember the start address before handling this segment */
|
||||
unsigned long StartAddr = Addr;
|
||||
|
||||
/* For computing FillLevel */
|
||||
unsigned long FillLevel;
|
||||
unsigned long FillAdded = 0;
|
||||
|
||||
/* Take note of "overwrite" segments and make sure there are no
|
||||
** other segment types following them in current memory region.
|
||||
*/
|
||||
@@ -2039,14 +2043,14 @@ unsigned CfgProcess (void)
|
||||
++Overflows;
|
||||
if (S->Flags & SF_OFFSET) {
|
||||
CfgWarning (GetSourcePos (S->LI),
|
||||
"Segment '%s' offset is too small in '%s' by %lu byte%c",
|
||||
"Segment '%s' offset is too small in '%s' by %lu byte%s",
|
||||
GetString (S->Name), GetString (M->Name),
|
||||
Addr - NewAddr, (Addr - NewAddr == 1) ? ' ' : 's');
|
||||
Addr - NewAddr, (Addr - NewAddr == 1) ? "" : "s");
|
||||
} else {
|
||||
CfgWarning (GetSourcePos (S->LI),
|
||||
"Segment '%s' start address is too low in '%s' by %lu byte%c",
|
||||
"Segment '%s' start address is too low in '%s' by %lu byte%s",
|
||||
GetString (S->Name), GetString (M->Name),
|
||||
Addr - NewAddr, (Addr - NewAddr == 1) ? ' ' : 's');
|
||||
Addr - NewAddr, (Addr - NewAddr == 1) ? "" : "s");
|
||||
}
|
||||
} else {
|
||||
Addr = NewAddr;
|
||||
@@ -2086,14 +2090,19 @@ unsigned CfgProcess (void)
|
||||
/* Increment the fill level of the memory area; and, check for an
|
||||
** overflow.
|
||||
*/
|
||||
M->FillLevel = Addr + S->Seg->Size - M->Start;
|
||||
if (M->FillLevel > M->Size && (M->Flags & MF_OVERFLOW) == 0) {
|
||||
FillLevel = Addr + S->Seg->Size - M->Start;
|
||||
if (FillLevel > M->Size && (M->Flags & MF_OVERFLOW) == 0) {
|
||||
++Overflows;
|
||||
M->Flags |= MF_OVERFLOW;
|
||||
CfgWarning (GetSourcePos (M->LI),
|
||||
"Segment '%s' overflows memory area '%s' by %lu byte%c",
|
||||
"Segment '%s' overflows memory area '%s' by %lu byte%s",
|
||||
GetString (S->Name), GetString (M->Name),
|
||||
M->FillLevel - M->Size, (M->FillLevel - M->Size == 1) ? ' ' : 's');
|
||||
FillLevel - M->Size, (FillLevel - M->Size == 1) ? "" : "s");
|
||||
}
|
||||
if (FillLevel > M->FillLevel) {
|
||||
/* Regular segments increase FillLevel. Overwrite segments may increase but not decrease FillLevel. */
|
||||
FillAdded = FillLevel - M->FillLevel;
|
||||
M->FillLevel = FillLevel;
|
||||
}
|
||||
|
||||
/* If requested, define symbols for the start and size of the
|
||||
@@ -2112,13 +2121,14 @@ unsigned CfgProcess (void)
|
||||
Addr += S->Seg->Size;
|
||||
|
||||
/* If this segment will go out to the file, or its place
|
||||
** in the file will be filled, then increase the file size,
|
||||
** unless it's an OVERWRITE segment.
|
||||
** in the file will be filled, then increase the file size.
|
||||
** An OVERWRITE segment will only increase the size if it overlapped some of the fill area.
|
||||
*/
|
||||
if (S->Load == M &&
|
||||
((S->Flags & SF_BSS) == 0 || (M->Flags & MF_FILL) != 0) &&
|
||||
(S->Flags & SF_OVERWRITE) == 0) {
|
||||
M->F->Size += Addr - StartAddr;
|
||||
((S->Flags & SF_BSS) == 0 || (M->Flags & MF_FILL) != 0)) {
|
||||
M->F->Size += (!(S->Flags & SF_OVERWRITE)) ?
|
||||
(Addr - StartAddr) :
|
||||
FillAdded;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -88,13 +88,13 @@ void InitSearchPaths (void)
|
||||
AddSubSearchPathFromEnv (CfgDefaultPath, "CC65_HOME", "cfg");
|
||||
|
||||
/* Add some compiled-in search paths if defined at compile time. */
|
||||
#if defined(LD65_LIB) && !defined(_WIN32)
|
||||
#if defined(LD65_LIB) && !defined(_WIN32) && !defined(_AMIGA)
|
||||
AddSearchPath (LibDefaultPath, LD65_LIB);
|
||||
#endif
|
||||
#if defined(LD65_OBJ) && !defined(_WIN32)
|
||||
#if defined(LD65_OBJ) && !defined(_WIN32) && !defined(_AMIGA)
|
||||
AddSearchPath (ObjDefaultPath, LD65_OBJ);
|
||||
#endif
|
||||
#if defined(LD65_CFG) && !defined(_WIN32)
|
||||
#if defined(LD65_CFG) && !defined(_WIN32) && !defined(_AMIGA)
|
||||
AddSearchPath (CfgDefaultPath, LD65_CFG);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -230,7 +230,7 @@ Section* ReadSection (FILE* F, ObjData* O)
|
||||
"%lu. Last module requiring alignment was '%s'.",
|
||||
GetString (Name), Alignment, MAX_ALIGNMENT,
|
||||
GetObjFileName (O));
|
||||
} else if (Alignment >= LARGE_ALIGNMENT && !LargeAlignment) {
|
||||
} else if (Alignment >= LARGE_ALIGNMENT && Alignment > S->Alignment && Alignment > Sec->Alignment && !LargeAlignment) {
|
||||
Warning ("Combined alignment for segment '%s' is suspiciously "
|
||||
"large (%lu). Last module requiring alignment was '%s'.",
|
||||
GetString (Name), Alignment, GetObjFileName (O));
|
||||
|
||||
@@ -312,7 +312,7 @@ static void AssembleByte(unsigned bits, char val)
|
||||
static unsigned char AnalyseNextChunks(signed *newlen, signed len, char data[32], char ColorBits)
|
||||
{
|
||||
char longest = 1;
|
||||
char prev = 255;
|
||||
unsigned char prev = 255;
|
||||
char count = 0;
|
||||
char index = 0;
|
||||
char lindex = 0;
|
||||
|
||||
Reference in New Issue
Block a user