Merge branch 'master' into ca65_jmp_abs_wrap_error
This commit is contained in:
@@ -496,7 +496,7 @@ static ExprNode* FuncIsMnemonic (void)
|
||||
/* Skip the name */
|
||||
NextTok ();
|
||||
|
||||
return GenLiteralExpr (Instr > 0);
|
||||
return GenLiteralExpr (Instr >= 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -118,7 +118,6 @@ void SetFeature (feature_t Feature, unsigned char On)
|
||||
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;
|
||||
|
||||
@@ -85,5 +85,4 @@ unsigned char OrgPerSeg = 0; /* Make .org local to current seg */
|
||||
unsigned char CComments = 0; /* Allow C like comments */
|
||||
unsigned char ForceRange = 0; /* Force values into expected range */
|
||||
unsigned char UnderlineInNumbers = 0; /* Allow underlines in numbers */
|
||||
unsigned char AddrSize = 0; /* Allow .ADDRSIZE function */
|
||||
unsigned char BracketAsIndirect = 0; /* Use '[]' not '()' for indirection */
|
||||
|
||||
@@ -87,7 +87,6 @@ extern unsigned char OrgPerSeg; /* Make .org local to current seg */
|
||||
extern unsigned char CComments; /* Allow C like comments */
|
||||
extern unsigned char ForceRange; /* Force values into expected range */
|
||||
extern unsigned char UnderlineInNumbers; /* Allow underlines in numbers */
|
||||
extern unsigned char AddrSize; /* Allow .ADDRSIZE function */
|
||||
extern unsigned char BracketAsIndirect; /* Use '[]' not '()' for indirection */
|
||||
|
||||
|
||||
|
||||
@@ -1043,6 +1043,11 @@ static void DoFeature (void)
|
||||
ErrorSkip ("Invalid feature: '%m%p'", &CurTok.SVal);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Feature == FEAT_ADDRSIZE) {
|
||||
Warning (1, "Deprecated feature: '.feature addrsize'. Pseudo function .addrsize is always available.");
|
||||
}
|
||||
|
||||
NextTok ();
|
||||
|
||||
/* Optional +/- or ON/OFF */
|
||||
|
||||
@@ -748,24 +748,7 @@ static token_t FindDotKeyword (void)
|
||||
R = bsearch (&K, DotKeywords, sizeof (DotKeywords) / sizeof (DotKeywords [0]),
|
||||
sizeof (DotKeywords [0]), CmpDotKeyword);
|
||||
if (R != 0) {
|
||||
|
||||
/* By default, disable any somewhat experiemental DotKeyword. */
|
||||
|
||||
switch (R->Tok) {
|
||||
|
||||
case TOK_ADDRSIZE:
|
||||
/* Disallow .ADDRSIZE function by default */
|
||||
if (AddrSize == 0) {
|
||||
return TOK_NONE;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return R->Tok;
|
||||
|
||||
} else {
|
||||
return TOK_NONE;
|
||||
}
|
||||
|
||||
@@ -79,6 +79,7 @@ IntStack WarnUnusedLabel = INTSTACK(1); /* - unused labels */
|
||||
IntStack WarnUnusedParam = INTSTACK(1); /* - unused parameters */
|
||||
IntStack WarnUnusedVar = INTSTACK(1); /* - unused variables */
|
||||
IntStack WarnUnusedFunc = INTSTACK(1); /* - unused functions */
|
||||
IntStack WarnConstOverflow = INTSTACK(0); /* - overflow conversion of numerical constants */
|
||||
|
||||
/* Map the name of a warning to the intstack that holds its state */
|
||||
typedef struct WarnMapEntry WarnMapEntry;
|
||||
@@ -102,6 +103,7 @@ static WarnMapEntry WarnMap[] = {
|
||||
{ &WarnUnusedLabel, "unused-label" },
|
||||
{ &WarnUnusedParam, "unused-param" },
|
||||
{ &WarnUnusedVar, "unused-var" },
|
||||
{ &WarnConstOverflow, "const-overflow" },
|
||||
};
|
||||
|
||||
Collection DiagnosticStrBufs;
|
||||
|
||||
@@ -76,6 +76,7 @@ extern IntStack WarnUnusedLabel; /* - unused labels */
|
||||
extern IntStack WarnUnusedParam; /* - unused parameters */
|
||||
extern IntStack WarnUnusedVar; /* - unused variables */
|
||||
extern IntStack WarnUnusedFunc; /* - unused functions */
|
||||
extern IntStack WarnConstOverflow; /* - overflow conversion of numerical constants */
|
||||
|
||||
/* Forward */
|
||||
struct StrBuf;
|
||||
|
||||
@@ -39,6 +39,8 @@
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
|
||||
/* common */
|
||||
#include "chartype.h"
|
||||
@@ -151,6 +153,11 @@ static const struct Keyword {
|
||||
#define IT_ULONG 0x08
|
||||
|
||||
|
||||
/* Internal type for numeric constant scanning.
|
||||
** Size must be explicit for cross-platform uniformity.
|
||||
*/
|
||||
typedef uint32_t scan_t;
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* code */
|
||||
@@ -521,7 +528,8 @@ static void NumericConst (void)
|
||||
int IsFloat;
|
||||
char C;
|
||||
unsigned DigitVal;
|
||||
unsigned long IVal; /* Value */
|
||||
scan_t IVal; /* Scanned value. */
|
||||
int Overflow;
|
||||
|
||||
/* Get the pp-number first, then parse on it */
|
||||
CopyPPNumber (&Src);
|
||||
@@ -575,6 +583,7 @@ static void NumericConst (void)
|
||||
/* Since we now know the correct base, convert the input into a number */
|
||||
SB_SetIndex (&Src, Index);
|
||||
IVal = 0;
|
||||
Overflow = 0;
|
||||
while ((C = SB_Peek (&Src)) != '\0' && (Base <= 10 ? IsDigit (C) : IsXDigit (C))) {
|
||||
DigitVal = HexVal (C);
|
||||
if (DigitVal >= Base) {
|
||||
@@ -582,9 +591,17 @@ static void NumericConst (void)
|
||||
SB_Clear (&Src);
|
||||
break;
|
||||
}
|
||||
IVal = (IVal * Base) + DigitVal;
|
||||
/* Test result of adding digit for overflow. */
|
||||
if (((scan_t)(IVal * Base + DigitVal) / Base) != IVal) {
|
||||
Overflow = 1;
|
||||
}
|
||||
IVal = IVal * Base + DigitVal;
|
||||
SB_Skip (&Src);
|
||||
}
|
||||
if (Overflow) {
|
||||
Error ("Numerical constant \"%s\" too large for internal %d-bit representation",
|
||||
SB_GetConstBuf (&Src), (int)(sizeof(IVal)*CHAR_BIT));
|
||||
}
|
||||
|
||||
/* Distinguish between integer and floating point constants */
|
||||
if (!IsFloat) {
|
||||
|
||||
@@ -793,6 +793,8 @@ static int HandleSymRedefinition (SymEntry* Sym, const Type* T, unsigned Flags)
|
||||
*/
|
||||
Error ("Redeclaration of enumerator constant '%s'", Sym->Name);
|
||||
Sym = 0;
|
||||
} else if (Flags & SC_STRUCTFIELD) {
|
||||
Error ("Duplicate member '%s'", Sym->Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1338,15 +1340,14 @@ SymEntry* AddGlobalSym (const char* Name, const Type* T, unsigned Flags)
|
||||
Name);
|
||||
Entry = 0;
|
||||
} else if ((Flags & SC_ESUTYPEMASK) != SC_TYPEDEF) {
|
||||
/* If a static declaration follows a non-static declaration, then
|
||||
** diagnose the conflict. It will warn and compile an extern
|
||||
** declaration if both declarations are global, otherwise give an
|
||||
** error.
|
||||
/* If a static declaration follows a non-static declaration, then the result is undefined.
|
||||
** Most compilers choose to either give an error at compile time,
|
||||
** or remove the extern property for a link time error if used.
|
||||
*/
|
||||
if (SymTab == SymTab0 &&
|
||||
(Flags & SC_EXTERN) == 0 &&
|
||||
(Entry->Flags & SC_EXTERN) != 0) {
|
||||
Warning ("Static declaration of '%s' follows non-static declaration", Name);
|
||||
Error ("Static declaration of '%s' follows non-static declaration", Name);
|
||||
} else if ((Flags & SC_EXTERN) != 0 &&
|
||||
(Entry->Owner == SymTab0 || (Entry->Flags & SC_DEF) != 0) &&
|
||||
(Entry->Flags & SC_EXTERN) == 0) {
|
||||
@@ -1358,8 +1359,12 @@ SymEntry* AddGlobalSym (const char* Name, const Type* T, unsigned Flags)
|
||||
*/
|
||||
if (Entry->Owner == SymTab0) {
|
||||
if ((Flags & SC_STORAGE) == 0) {
|
||||
/* Linkage must be unchanged */
|
||||
/* Linkage must be unchanged.
|
||||
** The C standard specifies that a later extern declaration will be ignored,
|
||||
** and will use the previous linkage instead. Giving a warning for this case.
|
||||
*/
|
||||
Flags &= ~SC_EXTERN;
|
||||
Warning ("Extern declaration of '%s' follows static declaration, extern ignored", Name);
|
||||
} else {
|
||||
Error ("Non-static declaration of '%s' follows static declaration", Name);
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
|
||||
|
||||
|
||||
static void DoConversion (ExprDesc* Expr, const Type* NewType)
|
||||
static void DoConversion (ExprDesc* Expr, const Type* NewType, int Explicit)
|
||||
/* Emit code to convert the given expression to a new type. */
|
||||
{
|
||||
const Type* OldType;
|
||||
@@ -128,6 +128,7 @@ static void DoConversion (ExprDesc* Expr, const Type* NewType)
|
||||
** internally already represented by a long.
|
||||
*/
|
||||
if (NewBits <= OldBits) {
|
||||
long OldVal = Expr->IVal;
|
||||
|
||||
/* Cut the value to the new size */
|
||||
Expr->IVal &= (0xFFFFFFFFUL >> (32 - NewBits));
|
||||
@@ -139,6 +140,10 @@ static void DoConversion (ExprDesc* Expr, const Type* NewType)
|
||||
Expr->IVal |= shl_l (~0UL, NewBits);
|
||||
}
|
||||
}
|
||||
|
||||
if ((OldVal != Expr->IVal) && IS_Get (&WarnConstOverflow) && !Explicit) {
|
||||
Warning ("Implicit conversion of constant overflows %d-bit destination", NewBits);
|
||||
}
|
||||
}
|
||||
|
||||
/* Do the integer constant <-> absolute address conversion if necessary */
|
||||
@@ -283,7 +288,7 @@ void TypeConversion (ExprDesc* Expr, const Type* NewType)
|
||||
/* Both types must be complete */
|
||||
if (!IsIncompleteESUType (NewType) && !IsIncompleteESUType (Expr->Type)) {
|
||||
/* Do the actual conversion */
|
||||
DoConversion (Expr, NewType);
|
||||
DoConversion (Expr, NewType, 0);
|
||||
} else {
|
||||
/* We should have already generated error elsewhere so that we
|
||||
** could just silently fail here to avoid excess errors, but to
|
||||
@@ -330,7 +335,7 @@ void TypeCast (ExprDesc* Expr)
|
||||
ReplaceType (Expr, NewType);
|
||||
} else if (IsCastType (Expr->Type)) {
|
||||
/* Convert the value. The result has always the new type */
|
||||
DoConversion (Expr, NewType);
|
||||
DoConversion (Expr, NewType, 1);
|
||||
} else {
|
||||
TypeCompatibilityDiagnostic (NewType, Expr->Type, 1,
|
||||
"Cast to incompatible type '%s' from '%s'");
|
||||
|
||||
@@ -850,14 +850,25 @@ static char *filterInput (FILE *F, char *tbl)
|
||||
/* loads file into buffer filtering it out */
|
||||
int a, prevchar = -1, i = 0, bracket = 0, quote = 1;
|
||||
|
||||
for (;;) {
|
||||
a = getc(F);
|
||||
if ((a == '\n') || (a == '\015')) a = ' ';
|
||||
if (a == ',' && quote) a = ' ';
|
||||
if (a == '\042') quote =! quote;
|
||||
a = getc(F);
|
||||
while (1) {
|
||||
if (i >= BLOODY_BIG_BUFFER) {
|
||||
AbEnd ("File too large for internal parsing buffer (%d bytes)",BLOODY_BIG_BUFFER);
|
||||
}
|
||||
if (((a == '\n') || (a == '\015')) ||
|
||||
(a == ',' && quote)) {
|
||||
a = ' ';
|
||||
}
|
||||
if (a == '\042') {
|
||||
quote =! quote;
|
||||
}
|
||||
if (quote) {
|
||||
if ((a == '{') || (a == '(')) bracket++;
|
||||
if ((a == '}') || (a == ')')) bracket--;
|
||||
if ((a == '{') || (a == '(')) {
|
||||
bracket++;
|
||||
}
|
||||
if ((a == '}') || (a == ')')) {
|
||||
bracket--;
|
||||
}
|
||||
}
|
||||
if (a == EOF) {
|
||||
tbl[i] = '\0';
|
||||
@@ -873,13 +884,18 @@ static char *filterInput (FILE *F, char *tbl)
|
||||
if (a == ';' && quote) {
|
||||
do {
|
||||
a = getc (F);
|
||||
} while (a != '\n');
|
||||
fseek (F, -1, SEEK_CUR);
|
||||
} while (a != '\n' && a != EOF);
|
||||
/* Don't discard this newline/EOF, continue to next loop.
|
||||
** A previous implementation used fseek(F,-1,SEEK_CUR),
|
||||
** which is invalid for text mode files, and was unreliable across platforms.
|
||||
*/
|
||||
continue;
|
||||
} else {
|
||||
tbl[i++] = a;
|
||||
prevchar = a;
|
||||
}
|
||||
}
|
||||
a = getc(F);
|
||||
}
|
||||
|
||||
if (bracket != 0) AbEnd ("There are unclosed brackets!");
|
||||
|
||||
@@ -64,18 +64,12 @@ static CPURegs Regs;
|
||||
/* Cycles for the current insn */
|
||||
static unsigned Cycles;
|
||||
|
||||
/* Total number of CPU cycles exec'd */
|
||||
static unsigned long TotalCycles;
|
||||
|
||||
/* NMI request active */
|
||||
static unsigned HaveNMIRequest;
|
||||
|
||||
/* IRQ request active */
|
||||
static unsigned HaveIRQRequest;
|
||||
|
||||
/* flag to print cycles at program termination */
|
||||
int PrintCycles;
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Helper functions and macros */
|
||||
@@ -3277,18 +3271,6 @@ unsigned ExecuteInsn (void)
|
||||
Handlers[CPU][OPC] ();
|
||||
}
|
||||
|
||||
/* Count cycles */
|
||||
TotalCycles += Cycles;
|
||||
|
||||
/* Return the number of clock cycles needed by this insn */
|
||||
return Cycles;
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned long GetCycles (void)
|
||||
/* Return the total number of cycles executed */
|
||||
{
|
||||
/* Return the total number of cycles */
|
||||
return TotalCycles;
|
||||
}
|
||||
|
||||
@@ -96,12 +96,6 @@ unsigned ExecuteInsn (void);
|
||||
** executed instruction.
|
||||
*/
|
||||
|
||||
unsigned long GetCycles (void);
|
||||
/* Return the total number of clock cycles executed */
|
||||
|
||||
extern int PrintCycles;
|
||||
/* flag to print cycles at program termination */
|
||||
|
||||
|
||||
/* End of 6502.h */
|
||||
|
||||
|
||||
@@ -41,6 +41,20 @@
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* flag to print cycles at program termination */
|
||||
int PrintCycles = 0;
|
||||
|
||||
/* cycles are counted by main.c */
|
||||
extern unsigned long long TotalCycles;
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
@@ -99,3 +113,14 @@ void Internal (const char* Format, ...)
|
||||
va_end (ap);
|
||||
exit (SIM65_ERROR);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SimExit (int Code)
|
||||
/* Exit the simulation with an exit code */
|
||||
{
|
||||
if (PrintCycles) {
|
||||
fprintf (stdout, "%llu cycles\n", TotalCycles);
|
||||
}
|
||||
exit (Code);
|
||||
}
|
||||
|
||||
@@ -49,12 +49,17 @@
|
||||
|
||||
|
||||
|
||||
#define SIM65_ERROR 0x7F
|
||||
/* Does not use EXIT_FAILURE because it may overlap with test results. */
|
||||
#define SIM65_ERROR -1
|
||||
/* An error result for errors that are not part of the simulated test.
|
||||
** Note that set simulated test can only return 8-bit errors 0-255.
|
||||
*/
|
||||
|
||||
#define SIM65_ERROR_TIMEOUT 0x7E
|
||||
#define SIM65_ERROR_TIMEOUT -2
|
||||
/* An error result for max CPU instructions exceeded. */
|
||||
|
||||
extern int PrintCycles;
|
||||
/* flag to print cycles at program termination */
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -75,6 +80,9 @@ void ErrorCode (int Code, const char* Format, ...) attribute((noreturn, format(p
|
||||
void Internal (const char* Format, ...) attribute((noreturn, format(printf,1,2)));
|
||||
/* Print an internal error message and die */
|
||||
|
||||
void SimExit (int Code);
|
||||
/* Exit the simulation with an exit code */
|
||||
|
||||
|
||||
|
||||
/* End of error.h */
|
||||
|
||||
@@ -60,8 +60,14 @@
|
||||
/* Name of program file */
|
||||
const char* ProgramFile;
|
||||
|
||||
/* exit simulator after MaxCycles Cycles */
|
||||
unsigned long MaxCycles;
|
||||
/* count of total cycles executed */
|
||||
unsigned long long TotalCycles = 0;
|
||||
|
||||
/* exit simulator after MaxCycles Cccles */
|
||||
unsigned long long MaxCycles = 0;
|
||||
|
||||
/* countdown from MaxCycles */
|
||||
unsigned long long RemainCycles;
|
||||
|
||||
/* Header signature 'sim65' */
|
||||
static const unsigned char HeaderSignature[] = {
|
||||
@@ -72,7 +78,6 @@ static const unsigned char HeaderSignature[] = {
|
||||
static const unsigned char HeaderVersion = 2;
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
@@ -139,7 +144,7 @@ static void OptQuitXIns (const char* Opt attribute ((unused)),
|
||||
const char* Arg attribute ((unused)))
|
||||
/* quit after MaxCycles cycles */
|
||||
{
|
||||
MaxCycles = strtoul(Arg, NULL, 0);
|
||||
MaxCycles = strtoull(Arg, NULL, 0);
|
||||
}
|
||||
|
||||
static unsigned char ReadProgramFile (void)
|
||||
@@ -184,6 +189,7 @@ static unsigned char ReadProgramFile (void)
|
||||
}
|
||||
|
||||
/* Get load address */
|
||||
Val2 = 0; /* suppress uninitialized variable warning */
|
||||
if (((Val = fgetc(F)) == EOF) ||
|
||||
((Val2 = fgetc(F)) == EOF)) {
|
||||
Error ("'%s': Header missing load address", ProgramFile);
|
||||
@@ -236,6 +242,7 @@ int main (int argc, char* argv[])
|
||||
|
||||
unsigned I;
|
||||
unsigned char SPAddr;
|
||||
unsigned int Cycles;
|
||||
|
||||
/* Initialize the cmdline module */
|
||||
InitCmdLine (&argc, &argv, "sim65");
|
||||
@@ -298,18 +305,24 @@ int main (int argc, char* argv[])
|
||||
MemInit ();
|
||||
|
||||
SPAddr = ReadProgramFile ();
|
||||
|
||||
ParaVirtInit (I, SPAddr);
|
||||
|
||||
Reset ();
|
||||
|
||||
RemainCycles = MaxCycles;
|
||||
while (1) {
|
||||
ExecuteInsn ();
|
||||
if (MaxCycles && (GetCycles () >= MaxCycles)) {
|
||||
ErrorCode (SIM65_ERROR_TIMEOUT, "Maximum number of cycles reached.");
|
||||
Cycles = ExecuteInsn ();
|
||||
TotalCycles += Cycles;
|
||||
if (MaxCycles) {
|
||||
if (Cycles > RemainCycles) {
|
||||
ErrorCode (SIM65_ERROR_TIMEOUT, "Maximum number of cycles reached.");
|
||||
}
|
||||
RemainCycles -= Cycles;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return an apropriate exit code */
|
||||
return EXIT_SUCCESS;
|
||||
/* Unreachable. sim65 program must exit through paravirtual PVExit
|
||||
** or timeout from MaxCycles producing an error.
|
||||
*/
|
||||
return SIM65_ERROR;
|
||||
}
|
||||
|
||||
@@ -124,11 +124,7 @@ static unsigned PopParam (unsigned char Incr)
|
||||
static void PVExit (CPURegs* Regs)
|
||||
{
|
||||
Print (stderr, 1, "PVExit ($%02X)\n", Regs->AC);
|
||||
if (PrintCycles) {
|
||||
Print (stdout, 0, "%lu cycles\n", GetCycles ());
|
||||
}
|
||||
|
||||
exit (Regs->AC);
|
||||
SimExit (Regs->AC); /* Error code in range 0-255. */
|
||||
}
|
||||
|
||||
|
||||
@@ -242,7 +238,15 @@ static void PVClose (CPURegs* Regs)
|
||||
|
||||
Print (stderr, 2, "PVClose ($%04X)\n", FD);
|
||||
|
||||
RetVal = close (FD);
|
||||
if (FD != 0xFFFF) {
|
||||
RetVal = close (FD);
|
||||
} else {
|
||||
/* test/val/constexpr.c "abuses" close, expecting close(-1) to return -1.
|
||||
** This behaviour is not the same on all target platforms.
|
||||
** MSVC's close treats it as a fatal error instead and terminates.
|
||||
*/
|
||||
RetVal = 0xFFFF;
|
||||
}
|
||||
|
||||
SetAX (Regs, RetVal);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user