From: cuz Date: Fri, 6 Jun 2003 20:47:59 +0000 (+0000) Subject: Completed assertions, add auto assertion for jmp (abs) bug X-Git-Tag: V2.12.0~1515 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=0d27afb21f17fd02fdd2806cf43ff56f4c5c5414;p=cc65 Completed assertions, add auto assertion for jmp (abs) bug git-svn-id: svn://svn.cc65.org/cc65/trunk@2203 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- diff --git a/src/ca65/asserts.c b/src/ca65/asserts.c new file mode 100644 index 000000000..25f5178fc --- /dev/null +++ b/src/ca65/asserts.c @@ -0,0 +1,137 @@ +/*****************************************************************************/ +/* */ +/* asserts.c */ +/* */ +/* Linker assertions for the ca65 crossassembler */ +/* */ +/* */ +/* */ +/* (C) 2003 Ullrich von Bassewitz */ +/* Römerstrasse 52 */ +/* D-70794 Filderstadt */ +/* EMail: uz@cc65.org */ +/* */ +/* */ +/* This software is provided 'as-is', without any expressed or implied */ +/* warranty. In no event will the authors be held liable for any damages */ +/* arising from the use of this software. */ +/* */ +/* Permission is granted to anyone to use this software for any purpose, */ +/* including commercial applications, and to alter it and redistribute it */ +/* freely, subject to the following restrictions: */ +/* */ +/* 1. The origin of this software must not be misrepresented; you must not */ +/* claim that you wrote the original software. If you use this software */ +/* in a product, an acknowledgment in the product documentation would be */ +/* appreciated but is not required. */ +/* 2. Altered source versions must be plainly marked as such, and must not */ +/* be misrepresented as being the original software. */ +/* 3. This notice may not be removed or altered from any source */ +/* distribution. */ +/* */ +/*****************************************************************************/ + + + +/* common */ +#include "coll.h" +#include "xmalloc.h" + +/* ca65 */ +#include "asserts.h" +#include "expr.h" +#include "objfile.h" +#include "scanner.h" + + + +/*****************************************************************************/ +/* Data */ +/*****************************************************************************/ + + + +/* An assertion entry */ +typedef struct Assertion Assertion; +struct Assertion { + ExprNode* Expr; /* Expression to evaluate */ + unsigned Action; /* Action to take */ + unsigned Msg; /* Message to print (if any) */ + FilePos Pos; /* File position of assertion */ +}; + +/* Collection with all assertions for a module */ +static Collection Assertions = STATIC_COLLECTION_INITIALIZER; + + + +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ + + + +static Assertion* NewAssertion (ExprNode* Expr, unsigned Action, unsigned Msg) +/* Create a new Assertion struct and return it */ +{ + /* Allocate memory */ + Assertion* A = xmalloc (sizeof (Assertion)); + + /* Initialize the fields */ + A->Expr = Expr; + A->Action = Action; + A->Msg = Msg; + A->Pos = CurPos; + + /* Return the new struct */ + return A; +} + + + +void AddAssertion (ExprNode* Expr, unsigned Action, unsigned Msg) +/* Add an assertion to the assertion table */ +{ + /* Add an assertion object to the table */ + CollAppend (&Assertions, NewAssertion (Expr, Action, Msg)); +} + + + +void WriteAssertions (void) +/* Write the assertion table to the object file */ +{ + unsigned I; + + /* Get the number of strings in the string pool */ + unsigned Count = CollCount (&Assertions); + + /* Tell the object file module that we're about to start the assertions */ + ObjStartAssertions (); + + /* Write the string count to the list */ + ObjWriteVar (Count); + + /* Write the assertions */ + for (I = 0; I < Count; ++I) { + + /* Get the next assertion */ + Assertion* A = CollAtUnchecked (&Assertions, I); + + /* Finalize the expression */ + A->Expr = FinalizeExpr (A->Expr); + + /* Write it to the file */ + WriteExpr (A->Expr); + ObjWriteVar (A->Action); + ObjWriteVar (A->Msg); + ObjWritePos (&A->Pos); + } + + /* Done writing the assertions */ + ObjEndAssertions (); +} + + + + diff --git a/src/ca65/asserts.h b/src/ca65/asserts.h new file mode 100644 index 000000000..0aef773a8 --- /dev/null +++ b/src/ca65/asserts.h @@ -0,0 +1,71 @@ +/*****************************************************************************/ +/* */ +/* asserts.h */ +/* */ +/* Linker assertions for the ca65 crossassembler */ +/* */ +/* */ +/* */ +/* (C) 2003 Ullrich von Bassewitz */ +/* Römerstrasse 52 */ +/* D-70794 Filderstadt */ +/* EMail: uz@cc65.org */ +/* */ +/* */ +/* This software is provided 'as-is', without any expressed or implied */ +/* warranty. In no event will the authors be held liable for any damages */ +/* arising from the use of this software. */ +/* */ +/* Permission is granted to anyone to use this software for any purpose, */ +/* including commercial applications, and to alter it and redistribute it */ +/* freely, subject to the following restrictions: */ +/* */ +/* 1. The origin of this software must not be misrepresented; you must not */ +/* claim that you wrote the original software. If you use this software */ +/* in a product, an acknowledgment in the product documentation would be */ +/* appreciated but is not required. */ +/* 2. Altered source versions must be plainly marked as such, and must not */ +/* be misrepresented as being the original software. */ +/* 3. This notice may not be removed or altered from any source */ +/* distribution. */ +/* */ +/*****************************************************************************/ + + + +#ifndef ASSERTS_H +#define ASSERTS_H + + + +/*****************************************************************************/ +/* Data */ +/*****************************************************************************/ + + + +/* Forwards */ +struct ExprNode; + + + +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ + + + +void AddAssertion (struct ExprNode* Expr, unsigned Action, unsigned Msg); +/* Add an assertion to the assertion table */ + +void WriteAssertions (void); +/* Write the assertion table to the object file */ + + + +/* End of asserts.h */ + +#endif + + + diff --git a/src/ca65/ea.c b/src/ca65/ea.c index 9bd5d3010..00303a47f 100644 --- a/src/ca65/ea.c +++ b/src/ca65/ea.c @@ -7,9 +7,9 @@ /* */ /* */ /* (C) 1998-2003 Ullrich von Bassewitz */ -/* Wacholderweg 14 */ -/* D-70597 Stuttgart */ -/* EMail: uz@musoftware.de */ +/* Römerstrasse 52 */ +/* D-70794 Filderstadt */ +/* EMail: uz@cc65.org */ /* */ /* */ /* This software is provided 'as-is', without any expressed or implied */ @@ -33,80 +33,81 @@ +/* ld65 */ #include "error.h" #include "expr.h" #include "instr.h" #include "nexttok.h" #include "ea.h" - + /*****************************************************************************/ -/* Code */ +/* Code */ /*****************************************************************************/ -void GetEA (unsigned long* AddrMode, ExprNode** Expr, ExprNode** Bank) -/* Parse an effective address, return the possible modes in AddrMode, and the - * expression involved (if any) in Expr. - */ +void GetEA (EffAddr* A) +/* Parse an effective address, return the result in A */ { - /* Clear the expressions */ - *Bank = *Expr = 0; + /* Clear the output struct */ + A->AddrModeSet = 0; + A->Bank = 0; + A->Expr = 0; if (TokIsSep (Tok)) { - *AddrMode = AM_IMPLICIT; + A->AddrModeSet = AM_IMPLICIT; } else if (Tok == TOK_HASH) { /* #val */ NextTok (); - *Expr = Expression (); - *AddrMode = AM_IMM; + A->Expr = Expression (); + A->AddrModeSet = AM_IMM; } else if (Tok == TOK_A) { NextTok (); - *AddrMode = AM_ACCU; + A->AddrModeSet = AM_ACCU; } else if (Tok == TOK_LBRACK) { /* [dir] or [dir],y */ NextTok (); - *Expr = Expression (); + A->Expr = Expression (); Consume (TOK_RBRACK, ERR_RBRACK_EXPECTED); if (Tok == TOK_COMMA) { /* [dir],y */ NextTok (); Consume (TOK_Y, ERR_Y_EXPECTED); - *AddrMode = AM_DIR_IND_LONG_Y; + A->AddrModeSet = AM_DIR_IND_LONG_Y; } else { /* [dir] */ - *AddrMode = AM_DIR_IND_LONG; + A->AddrModeSet = AM_DIR_IND_LONG; } } else if (Tok == TOK_LPAREN) { /* One of the indirect modes */ NextTok (); - *Expr = Expression (); + A->Expr = Expression (); if (Tok == TOK_COMMA) { /* (expr,X) or (rel,S),y */ NextTok (); if (Tok == TOK_X) { - /* (adr,x) */ - NextTok (); - *AddrMode = AM_ABS_X_IND | AM_DIR_X_IND; - ConsumeRParen (); + /* (adr,x) */ + NextTok (); + A->AddrModeSet = AM_ABS_X_IND | AM_DIR_X_IND; + ConsumeRParen (); } else if (Tok == TOK_S) { - /* (rel,s),y */ + /* (rel,s),y */ NextTok (); - *AddrMode = AM_STACK_REL_IND_Y; + A->AddrModeSet = AM_STACK_REL_IND_Y; ConsumeRParen (); ConsumeComma (); Consume (TOK_Y, ERR_Y_EXPECTED); @@ -122,10 +123,10 @@ void GetEA (unsigned long* AddrMode, ExprNode** Expr, ExprNode** Bank) /* (adr),y */ NextTok (); Consume (TOK_Y, ERR_Y_EXPECTED); - *AddrMode = AM_DIR_IND_Y; + A->AddrModeSet = AM_DIR_IND_Y; } else { /* (adr) */ - *AddrMode = AM_ABS_IND | AM_DIR_IND; + A->AddrModeSet = AM_ABS_IND | AM_DIR_IND; } } @@ -140,22 +141,22 @@ void GetEA (unsigned long* AddrMode, ExprNode** Expr, ExprNode** Bank) * adr,y * adr,s */ - *Expr = Expression (); + A->Expr = Expression (); if (Tok == TOK_DOT) { /* Expr was a bank specification: bank.adr or bank.adr,x */ - *Bank = *Expr; + A->Bank = A->Expr; NextTok (); - *Expr = Expression (); + A->Expr = Expression (); if (Tok == TOK_COMMA) { - /* bank.adr,x */ - NextTok (); - Consume (TOK_X, ERR_X_EXPECTED); - *AddrMode = AM_ABS_LONG_X; + /* bank.adr,x */ + NextTok (); + Consume (TOK_X, ERR_X_EXPECTED); + A->AddrModeSet = AM_ABS_LONG_X; } else { /* bank.adr */ - *AddrMode = AM_ABS_LONG; + A->AddrModeSet = AM_ABS_LONG; } } else { @@ -166,17 +167,17 @@ void GetEA (unsigned long* AddrMode, ExprNode** Expr, ExprNode** Bank) switch (Tok) { case TOK_X: - *AddrMode = AM_ABS_X | AM_DIR_X; + A->AddrModeSet = AM_ABS_X | AM_DIR_X; NextTok (); break; case TOK_Y: - *AddrMode = AM_ABS_Y | AM_DIR_Y; + A->AddrModeSet = AM_ABS_Y | AM_DIR_Y; NextTok (); break; case TOK_S: - *AddrMode = AM_STACK_REL; + A->AddrModeSet = AM_STACK_REL; NextTok (); break; @@ -185,9 +186,9 @@ void GetEA (unsigned long* AddrMode, ExprNode** Expr, ExprNode** Bank) } - } else { + } else { - *AddrMode = AM_ABS | AM_DIR; + A->AddrModeSet = AM_ABS | AM_DIR; } } diff --git a/src/ca65/ea.h b/src/ca65/ea.h index 8d3c88a8d..9bc6c1ba3 100644 --- a/src/ca65/ea.h +++ b/src/ca65/ea.h @@ -1,15 +1,15 @@ /*****************************************************************************/ /* */ -/* ea.h */ +/* ea.h */ /* */ /* Effective address parsing for the ca65 macroassembler */ /* */ /* */ /* */ -/* (C) 1998 Ullrich von Bassewitz */ -/* Wacholderweg 14 */ -/* D-70597 Stuttgart */ -/* EMail: uz@musoftware.de */ +/* (C) 1998-2003 Ullrich von Bassewitz */ +/* Römerstrasse 52 */ +/* D-70794 Filderstadt */ +/* EMail: uz@cc65.org */ /* */ /* */ /* This software is provided 'as-is', without any expressed or implied */ @@ -38,26 +38,36 @@ -#include "expr.h" +/*****************************************************************************/ +/* Data */ +/*****************************************************************************/ -/*****************************************************************************/ -/* Data */ -/*****************************************************************************/ +/* GetEA result struct */ +typedef struct EffAddr EffAddr; +struct EffAddr { + /* First three fields get filled when calling GetEA */ + unsigned long AddrModeSet; /* Possible addressing modes */ + struct ExprNode* Expr; /* Expression if any (NULL otherwise) */ + struct ExprNode* Bank; /* Bank expression if any */ + + /* The following fields are used inside instr.c */ + unsigned AddrMode; /* Actual addressing mode used */ + unsigned long AddrModeBit; /* Addressing mode as bit mask */ + unsigned char Opcode; /* Opcode */ +}; /*****************************************************************************/ -/* Code */ +/* Code */ /*****************************************************************************/ -void GetEA (unsigned long* AddrMode, ExprNode** Expr, ExprNode** Bank); -/* Parse an effective address, return the possible modes in AddrMode, and the - * expression involved (if any) in Expr. - */ +void GetEA (EffAddr* A); +/* Parse an effective address, return the result in A */ diff --git a/src/ca65/expr.c b/src/ca65/expr.c index 42c90d154..af26c0dfe 100644 --- a/src/ca65/expr.c +++ b/src/ca65/expr.c @@ -7,9 +7,9 @@ /* */ /* */ /* (C) 1998-2003 Ullrich von Bassewitz */ -/* Wacholderweg 14 */ -/* D-70597 Stuttgart */ -/* EMail: uz@musoftware.de */ +/* Römerstrasse 52 */ +/* D-70794 Filderstadt */ +/* EMail: uz@cc65.org */ /* */ /* */ /* This software is provided 'as-is', without any expressed or implied */ @@ -951,6 +951,18 @@ long ConstExpression (void) +void FreeExpr (ExprNode* Root) +/* Free the expression, Root is pointing to. */ +{ + if (Root) { + FreeExpr (Root->Left); + FreeExpr (Root->Right); + FreeExprNode (Root); + } +} + + + ExprNode* LiteralExpr (long Val) /* Return an expression tree that encodes the given literal value */ { @@ -1050,14 +1062,16 @@ ExprNode* ULabelExpr (unsigned Num) -void FreeExpr (ExprNode* Root) -/* Free the expression, Root is pointing to. */ +ExprNode* ForceByteExpr (ExprNode* Expr) +/* Force the given expression into a byte and return the result */ { - if (Root) { - FreeExpr (Root->Left); - FreeExpr (Root->Right); - FreeExprNode (Root); - } + /* Use the low byte operator to force the expression into byte size */ + ExprNode* Root = NewExprNode (); + Root->Left = Expr; + Root->Op = EXPR_BYTE0; + + /* Return the result */ + return Root; } @@ -1065,7 +1079,7 @@ void FreeExpr (ExprNode* Root) ExprNode* ForceWordExpr (ExprNode* Expr) /* Force the given expression into a word and return the result. */ { - /* And the expression by $FFFF to force it into word size */ + /* AND the expression by $FFFF to force it into word size */ ExprNode* Root = NewExprNode (); Root->Left = Expr; Root->Op = EXPR_AND; @@ -1077,6 +1091,21 @@ ExprNode* ForceWordExpr (ExprNode* Expr) +ExprNode* CompareExpr (ExprNode* Expr, long Val) +/* Generate an expression that compares Expr and Val for equality */ +{ + /* Generate a compare node */ + ExprNode* Root = NewExprNode (); + Root->Left = Expr; + Root->Op = EXPR_EQ; + Root->Right = LiteralExpr (Val); + + /* Return the result */ + return Root; +} + + + int IsConstExpr (ExprNode* Root) /* Return true if the given expression is a constant expression, that is, one * with no references to external symbols. diff --git a/src/ca65/expr.h b/src/ca65/expr.h index b1ead1bc4..7338b193e 100644 --- a/src/ca65/expr.h +++ b/src/ca65/expr.h @@ -6,10 +6,10 @@ /* */ /* */ /* */ -/* (C) 1998 Ullrich von Bassewitz */ -/* Wacholderweg 14 */ -/* D-70597 Stuttgart */ -/* EMail: uz@musoftware.de */ +/* (C) 1998-2003 Ullrich von Bassewitz */ +/* Römerstrasse 52 */ +/* D-70794 Filderstadt */ +/* EMail: uz@cc65.org */ /* */ /* */ /* This software is provided 'as-is', without any expressed or implied */ @@ -80,9 +80,15 @@ ExprNode* BranchExpr (unsigned Offs); ExprNode* ULabelExpr (unsigned Num); /* Return an expression for an unnamed label with the given index */ +ExprNode* ForceByteExpr (ExprNode* Expr); +/* Force the given expression into a byte and return the result */ + ExprNode* ForceWordExpr (ExprNode* Expr); /* Force the given expression into a word and return the result. */ +ExprNode* CompareExpr (ExprNode* Expr, long Val); +/* Generate an expression that compares Expr and Val for equality */ + int IsConstExpr (ExprNode* Root); /* Return true if the given expression is a constant expression, that is, one * with no references to external symbols. diff --git a/src/ca65/instr.c b/src/ca65/instr.c index 6cd78b62c..c39096aed 100644 --- a/src/ca65/instr.c +++ b/src/ca65/instr.c @@ -38,18 +38,21 @@ #include /* common */ +#include "assertdefs.h" #include "bitops.h" #include "check.h" /* ca65 */ +#include "asserts.h" #include "ea.h" #include "error.h" #include "expr.h" #include "global.h" +#include "instr.h" #include "nexttok.h" #include "objcode.h" +#include "spool.h" #include "symtab.h" -#include "instr.h" @@ -65,6 +68,7 @@ static void PutPCRel16 (const InsDesc* Ins); static void PutBlockMove (const InsDesc* Ins); static void PutREP (const InsDesc* Ins); static void PutSEP (const InsDesc* Ins); +static void PutJmp (const InsDesc* Ins); static void PutAll (const InsDesc* Ins); @@ -89,7 +93,7 @@ static const struct { { "BPL", 0x0020000, 0x10, 0, PutPCRel8 }, { "BRK", 0x0000001, 0x00, 0, PutAll }, { "BVC", 0x0020000, 0x50, 0, PutPCRel8 }, - { "BVS", 0x0020000, 0x70, 0, PutPCRel8 }, + { "BVS", 0x0020000, 0x70, 0, PutPCRel8 }, { "CLC", 0x0000001, 0x18, 0, PutAll }, { "CLD", 0x0000001, 0xd8, 0, PutAll }, { "CLI", 0x0000001, 0x58, 0, PutAll }, @@ -104,7 +108,7 @@ static const struct { { "INC", 0x000006c, 0x00, 4, PutAll }, { "INX", 0x0000001, 0xe8, 0, PutAll }, { "INY", 0x0000001, 0xc8, 0, PutAll }, - { "JMP", 0x0000808, 0x4c, 6, PutAll }, + { "JMP", 0x0000808, 0x4c, 6, PutJmp }, { "JSR", 0x0000008, 0x20, 7, PutAll }, { "LDA", 0x080A26C, 0xa0, 0, PutAll }, { "LDX", 0x080030C, 0xa2, 1, PutAll }, @@ -132,7 +136,7 @@ static const struct { { "TSX", 0x0000001, 0xba, 0, PutAll }, { "TXA", 0x0000001, 0x8a, 0, PutAll }, { "TXS", 0x0000001, 0x9a, 0, PutAll }, - { "TYA", 0x0000001, 0x98, 0, PutAll } + { "TYA", 0x0000001, 0x98, 0, PutAll } } }; @@ -175,7 +179,7 @@ static const struct { { "INX", 0x0000001, 0xe8, 0, PutAll }, { "INY", 0x0000001, 0xc8, 0, PutAll }, { "JMP", 0x0010808, 0x4c, 6, PutAll }, - { "JSR", 0x0000008, 0x20, 7, PutAll }, + { "JSR", 0x0000008, 0x20, 7, PutAll }, { "LDA", 0x080A66C, 0xa0, 0, PutAll }, { "LDX", 0x080030C, 0xa2, 1, PutAll }, { "LDY", 0x080006C, 0xa0, 1, PutAll }, @@ -261,7 +265,7 @@ static const struct { { "JSL", 0x0000010, 0x20, 7, PutAll }, { "JSR", 0x0010018, 0x20, 7, PutAll }, { "LDA", 0x0b8f6fc, 0xa0, 0, PutAll }, - { "LDX", 0x0c0030c, 0xa2, 1, PutAll }, + { "LDX", 0x0c0030c, 0xa2, 1, PutAll }, { "LDY", 0x0c0006c, 0xa0, 1, PutAll }, { "LSR", 0x000006F, 0x42, 1, PutAll }, { "MVN", 0x1000000, 0x54, 0, PutBlockMove }, @@ -304,7 +308,7 @@ static const struct { { "TAD", 0x0000001, 0x5b, 0, PutAll }, /* == TCD */ { "TAS", 0x0000001, 0x1b, 0, PutAll }, /* == TCS */ { "TAX", 0x0000001, 0xaa, 0, PutAll }, - { "TAY", 0x0000001, 0xa8, 0, PutAll }, + { "TAY", 0x0000001, 0xa8, 0, PutAll }, { "TCD", 0x0000001, 0x5b, 0, PutAll }, { "TCS", 0x0000001, 0x1b, 0, PutAll }, { "TDA", 0x0000001, 0x7b, 0, PutAll }, /* == TDC */ @@ -437,62 +441,142 @@ unsigned char ExtBytes [AMI_COUNT] = { /*****************************************************************************/ -/* Handler functions */ +/* Handler functions */ /*****************************************************************************/ -static long PutImmed8 (const InsDesc* Ins) -/* Parse and emit an immediate 8 bit instruction. Return the value of the - * operand if it's available and const. +static int EvalEA (const InsDesc* Ins, EffAddr* A) +/* Evaluate the effective address. All fields in A will be valid after calling + * this function. The function returns true on success and false on errors. */ { - ExprNode* Expr; - ExprNode* Bank; - unsigned long AddrMode; - unsigned char OpCode; - long Val = -1; - - /* Get the addressing mode used */ - GetEA (&AddrMode, &Expr, &Bank); + /* Get the set of possible addressing modes */ + GetEA (A); /* From the possible addressing modes, remove the ones that are invalid * for this instruction or CPU. */ - AddrMode &= Ins->AddrMode; + A->AddrModeSet &= Ins->AddrMode; /* If we have possible zero page addressing modes, and the expression * involved (if any) is not in byte range, remove the zero page addressing * modes. */ - if (Expr && (AddrMode & AM_ZP) && !IsByteExpr (Expr)) { - AddrMode &= ~AM_ZP; + if (A->Expr && (A->AddrModeSet & AM_ZP) && !IsByteExpr (A->Expr)) { + A->AddrModeSet &= ~AM_ZP; } /* Check if we have any adressing modes left */ - if (AddrMode == 0) { - Error (ERR_ILLEGAL_ADDR_MODE); - return -1; + if (A->AddrModeSet == 0) { + Error (ERR_ILLEGAL_ADDR_MODE); + return 0; + } + A->AddrMode = BitFind (A->AddrModeSet); + A->AddrModeBit = (0x01UL << A->AddrMode); + + /* If the instruction has a one byte operand and immediate addressing is + * allowed but not used, check for an operand expression in the form + *