diff --git a/Makefile b/Makefile index d9ee6eeb..96b08cd8 100644 --- a/Makefile +++ b/Makefile @@ -54,7 +54,6 @@ all: rgbasm rgblink rgbfix rgbgfx rgbasm_obj := \ src/asm/asmy.o \ src/asm/charmap.o \ - src/asm/constexpr.o \ src/asm/fstack.o \ src/asm/globlex.o \ src/asm/lexer.o \ diff --git a/include/asm/constexpr.h b/include/asm/constexpr.h deleted file mode 100644 index 1e566e53..00000000 --- a/include/asm/constexpr.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * This file is part of RGBDS. - * - * Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors. - * - * SPDX-License-Identifier: MIT - */ - -#ifndef RGBDS_ASM_CONSTEXPR_H -#define RGBDS_ASM_CONSTEXPR_H - -#include - -struct ConstExpression { - union { - int32_t nVal; - struct sSymbol *pSym; - } u; - uint32_t isSym; -}; - -void constexpr_Symbol(struct ConstExpression *expr, char *tzSym); -void constexpr_BankSymbol(struct ConstExpression *expr, char *tzSym); -void constexpr_BankSection(struct ConstExpression *expr, char *tzSym); -void constexpr_Number(struct ConstExpression *expr, int32_t i); -void constexpr_UnaryOp(struct ConstExpression *expr, - int32_t op, - const struct ConstExpression *src); -void constexpr_BinaryOp(struct ConstExpression *expr, - int32_t op, - const struct ConstExpression *src1, - const struct ConstExpression *src2); -int32_t constexpr_GetConstantValue(struct ConstExpression *expr); - -#endif /* RGBDS_ASM_CONSTEXPR_H */ diff --git a/include/asm/rpn.h b/include/asm/rpn.h index 8ee9e3f1..38de7fc1 100644 --- a/include/asm/rpn.h +++ b/include/asm/rpn.h @@ -10,62 +10,36 @@ #define RGBDS_ASM_RPN_H #include +#include + +#include "linkdefs.h" #define MAXRPNLEN 1048576 struct Expression { - int32_t nVal; - uint8_t *tRPN; - uint32_t nRPNCapacity; - uint32_t nRPNLength; - uint32_t nRPNPatchSize; - uint32_t nRPNOut; - uint32_t isReloc; + int32_t nVal; // If the expression's value is known, it's here + char *reason; // Why the expression is not known, if it isn't + bool isKnown; // Whether the expression's value is known + bool isSymbol; // Whether the expression represents a symbol + uint8_t *tRPN; // Array of bytes serializing the RPN expression + uint32_t nRPNCapacity; // Size of the `tRPN` buffer + uint32_t nRPNLength; // Used size of the `tRPN` buffer + uint32_t nRPNPatchSize; // Size the expression will take in the obj file + // FIXME: does this need to be part of the struct? + uint32_t nRPNOut; // How many bytes have been written }; /* FIXME: Should be defined in `asmy.h`, but impossible with POSIX Yacc */ extern int32_t nPCOffset; -uint32_t rpn_isReloc(const struct Expression *expr); +bool rpn_isKnown(const struct Expression *expr); +bool rpn_isSymbol(const struct Expression *expr); void rpn_Symbol(struct Expression *expr, char *tzSym); void rpn_Number(struct Expression *expr, uint32_t i); void rpn_LOGNOT(struct Expression *expr, const struct Expression *src); -void rpn_LOGOR(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2); -void rpn_LOGAND(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2); -void rpn_LOGEQU(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2); -void rpn_LOGGT(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2); -void rpn_LOGLT(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2); -void rpn_LOGGE(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2); -void rpn_LOGLE(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2); -void rpn_LOGNE(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2); -void rpn_ADD(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2); -void rpn_SUB(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2); -void rpn_XOR(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2); -void rpn_OR(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2); -void rpn_AND(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2); -void rpn_SHL(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2); -void rpn_SHR(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2); -void rpn_MUL(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2); -void rpn_DIV(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2); -void rpn_MOD(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2); +void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr, + const struct Expression *src1, + const struct Expression *src2); void rpn_HIGH(struct Expression *expr, const struct Expression *src); void rpn_LOW(struct Expression *expr, const struct Expression *src); void rpn_UNNEG(struct Expression *expr, const struct Expression *src); diff --git a/src/asm/asmy.y b/src/asm/asmy.y index 11169634..4406ead6 100644 --- a/src/asm/asmy.y +++ b/src/asm/asmy.y @@ -18,7 +18,6 @@ #include "asm/asm.h" #include "asm/charmap.h" -#include "asm/constexpr.h" #include "asm/fstack.h" #include "asm/lexer.h" #include "asm/main.h" @@ -510,11 +509,10 @@ static void strsubUTF8(char *dest, const char *src, uint32_t pos, uint32_t len) char tzString[MAXSTRLEN + 1]; struct Expression sVal; int32_t nConstValue; - struct ConstExpression sConstExpr; } %type relocconst -%type const +%type const %type uconst %type const_3bit %type const_8bit @@ -966,17 +964,17 @@ global_list_entry : T_ID equ : T_LABEL T_POP_EQU const { - sym_AddEqu($1, constexpr_GetConstantValue(&$3)); + sym_AddEqu($1, $3); } ; set : T_LABEL T_POP_SET const { - sym_AddSet($1, constexpr_GetConstantValue(&$3)); + sym_AddSet($1, $3); } | T_LABEL T_POP_EQUAL const { - sym_AddSet($1, constexpr_GetConstantValue(&$3)); + sym_AddSet($1, $3); } ; @@ -1004,12 +1002,10 @@ incbin : T_POP_INCBIN string charmap : T_POP_CHARMAP string comma const { - int32_t value = constexpr_GetConstantValue(&$4); - - if ((value & 0xFF) != value) + if (($4 & 0xFF) != $4) warning(WARNING_TRUNCATION, "Expression must be 8-bit"); - if (charmap_Add($2, value & 0xFF) == -1) + if (charmap_Add($2, $4 & 0xFF) == -1) yyerror("Error parsing charmap. Either you've added too many (%i), or the input character length is too long (%i)' : %s\n", MAXCHARMAPS, CHARMAPLENGTH, strerror(errno)); } ; @@ -1044,26 +1040,26 @@ printt : T_POP_PRINTT string printv : T_POP_PRINTV const { - printf("$%X", constexpr_GetConstantValue(&$2)); + printf("$%X", $2); } ; printi : T_POP_PRINTI const { - printf("%d", constexpr_GetConstantValue(&$2)); + printf("%d", $2); } ; printf : T_POP_PRINTF const { - math_Print(constexpr_GetConstantValue(&$2)); + math_Print($2); } ; if : T_POP_IF const { nIFDepth++; - if (!constexpr_GetConstantValue(&$2)) { + if (!$2) { /* * Continue parsing after ELSE, or at ELIF or * ENDC keyword. @@ -1095,7 +1091,7 @@ elif : T_POP_ELIF const */ skipElif = true; - if (!constexpr_GetConstantValue(&$2)) { + if (!$2) { /* * Continue parsing after ELSE, or at * ELIF or ENDC keyword. @@ -1127,7 +1123,7 @@ endc : T_POP_ENDC const_3bit : const { - int32_t value = constexpr_GetConstantValue(&$1); + int32_t value = $1; if ((value < 0) || (value > 7)) yyerror("Immediate value must be 3-bit"); else @@ -1190,7 +1186,7 @@ constlist_32bit_entry : /* empty */ const_8bit : relocconst { - if( (!rpn_isReloc(&$1)) && (($1.nVal < -128) || ($1.nVal > 255)) ) + if( (rpn_isKnown(&$1)) && (($1.nVal < -128) || ($1.nVal > 255)) ) warning(WARNING_TRUNCATION, "Expression must be 8-bit"); $$ = $1; } @@ -1198,7 +1194,7 @@ const_8bit : relocconst const_16bit : relocconst { - if ((!rpn_isReloc(&$1)) && (($1.nVal < -32768) || ($1.nVal > 65535))) + if ((rpn_isKnown(&$1)) && (($1.nVal < -32768) || ($1.nVal > 65535))) warning(WARNING_TRUNCATION, "Expression must be 16-bit"); $$ = $1; } @@ -1223,24 +1219,24 @@ relocconst : T_ID rpn_Number(&$$, r); } | T_OP_LOGICNOT relocconst %prec NEG { rpn_LOGNOT(&$$, &$2); } - | relocconst T_OP_LOGICOR relocconst { rpn_LOGOR(&$$, &$1, &$3); } - | relocconst T_OP_LOGICAND relocconst { rpn_LOGAND(&$$, &$1, &$3); } - | relocconst T_OP_LOGICEQU relocconst { rpn_LOGEQU(&$$, &$1, &$3); } - | relocconst T_OP_LOGICGT relocconst { rpn_LOGGT(&$$, &$1, &$3); } - | relocconst T_OP_LOGICLT relocconst { rpn_LOGLT(&$$, &$1, &$3); } - | relocconst T_OP_LOGICGE relocconst { rpn_LOGGE(&$$, &$1, &$3); } - | relocconst T_OP_LOGICLE relocconst { rpn_LOGLE(&$$, &$1, &$3); } - | relocconst T_OP_LOGICNE relocconst { rpn_LOGNE(&$$, &$1, &$3); } - | relocconst T_OP_ADD relocconst { rpn_ADD(&$$, &$1, &$3); } - | relocconst T_OP_SUB relocconst { rpn_SUB(&$$, &$1, &$3); } - | relocconst T_OP_XOR relocconst { rpn_XOR(&$$, &$1, &$3); } - | relocconst T_OP_OR relocconst { rpn_OR(&$$, &$1, &$3); } - | relocconst T_OP_AND relocconst { rpn_AND(&$$, &$1, &$3); } - | relocconst T_OP_SHL relocconst { rpn_SHL(&$$, &$1, &$3); } - | relocconst T_OP_SHR relocconst { rpn_SHR(&$$, &$1, &$3); } - | relocconst T_OP_MUL relocconst { rpn_MUL(&$$, &$1, &$3); } - | relocconst T_OP_DIV relocconst { rpn_DIV(&$$, &$1, &$3); } - | relocconst T_OP_MOD relocconst { rpn_MOD(&$$, &$1, &$3); } + | relocconst T_OP_LOGICOR relocconst { rpn_BinaryOp(RPN_LOGOR, &$$, &$1, &$3); } + | relocconst T_OP_LOGICAND relocconst { rpn_BinaryOp(RPN_LOGAND, &$$, &$1, &$3); } + | relocconst T_OP_LOGICEQU relocconst { rpn_BinaryOp(RPN_LOGEQ, &$$, &$1, &$3); } + | relocconst T_OP_LOGICGT relocconst { rpn_BinaryOp(RPN_LOGGT, &$$, &$1, &$3); } + | relocconst T_OP_LOGICLT relocconst { rpn_BinaryOp(RPN_LOGLT, &$$, &$1, &$3); } + | relocconst T_OP_LOGICGE relocconst { rpn_BinaryOp(RPN_LOGGE, &$$, &$1, &$3); } + | relocconst T_OP_LOGICLE relocconst { rpn_BinaryOp(RPN_LOGLE, &$$, &$1, &$3); } + | relocconst T_OP_LOGICNE relocconst { rpn_BinaryOp(RPN_LOGNE, &$$, &$1, &$3); } + | relocconst T_OP_ADD relocconst { rpn_BinaryOp(RPN_ADD, &$$, &$1, &$3); } + | relocconst T_OP_SUB relocconst { rpn_BinaryOp(RPN_SUB, &$$, &$1, &$3); } + | relocconst T_OP_XOR relocconst { rpn_BinaryOp(RPN_XOR, &$$, &$1, &$3); } + | relocconst T_OP_OR relocconst { rpn_BinaryOp(RPN_OR, &$$, &$1, &$3); } + | relocconst T_OP_AND relocconst { rpn_BinaryOp(RPN_AND, &$$, &$1, &$3); } + | relocconst T_OP_SHL relocconst { rpn_BinaryOp(RPN_SHL, &$$, &$1, &$3); } + | relocconst T_OP_SHR relocconst { rpn_BinaryOp(RPN_SHR, &$$, &$1, &$3); } + | relocconst T_OP_MUL relocconst { rpn_BinaryOp(RPN_MUL, &$$, &$1, &$3); } + | relocconst T_OP_DIV relocconst { rpn_BinaryOp(RPN_DIV, &$$, &$1, &$3); } + | relocconst T_OP_MOD relocconst { rpn_BinaryOp(RPN_MOD, &$$, &$1, &$3); } | T_OP_ADD relocconst %prec NEG { $$ = $2; } | T_OP_SUB relocconst %prec NEG { rpn_UNNEG(&$$, &$2); } | T_OP_NOT relocconst %prec NEG { rpn_UNNOT(&$$, &$2); } @@ -1268,57 +1264,57 @@ relocconst : T_ID } | T_OP_ROUND '(' const ')' { - rpn_Number(&$$, math_Round(constexpr_GetConstantValue(&$3))); + rpn_Number(&$$, math_Round($3)); } | T_OP_CEIL '(' const ')' { - rpn_Number(&$$, math_Ceil(constexpr_GetConstantValue(&$3))); + rpn_Number(&$$, math_Ceil($3)); } | T_OP_FLOOR '(' const ')' { - rpn_Number(&$$, math_Floor(constexpr_GetConstantValue(&$3))); + rpn_Number(&$$, math_Floor($3)); } | T_OP_FDIV '(' const comma const ')' { rpn_Number(&$$, - math_Div(constexpr_GetConstantValue(&$3), - constexpr_GetConstantValue(&$5))); + math_Div($3, + $5)); } | T_OP_FMUL '(' const comma const ')' { rpn_Number(&$$, - math_Mul(constexpr_GetConstantValue(&$3), - constexpr_GetConstantValue(&$5))); + math_Mul($3, + $5)); } | T_OP_SIN '(' const ')' { - rpn_Number(&$$, math_Sin(constexpr_GetConstantValue(&$3))); + rpn_Number(&$$, math_Sin($3)); } | T_OP_COS '(' const ')' { - rpn_Number(&$$, math_Cos(constexpr_GetConstantValue(&$3))); + rpn_Number(&$$, math_Cos($3)); } | T_OP_TAN '(' const ')' { - rpn_Number(&$$, math_Tan(constexpr_GetConstantValue(&$3))); + rpn_Number(&$$, math_Tan($3)); } | T_OP_ASIN '(' const ')' { - rpn_Number(&$$, math_ASin(constexpr_GetConstantValue(&$3))); + rpn_Number(&$$, math_ASin($3)); } | T_OP_ACOS '(' const ')' { - rpn_Number(&$$, math_ACos(constexpr_GetConstantValue(&$3))); + rpn_Number(&$$, math_ACos($3)); } | T_OP_ATAN '(' const ')' { - rpn_Number(&$$, math_ATan(constexpr_GetConstantValue(&$3))); + rpn_Number(&$$, math_ATan($3)); } | T_OP_ATAN2 '(' const comma const ')' { rpn_Number(&$$, - math_ATan2(constexpr_GetConstantValue(&$3), - constexpr_GetConstantValue(&$5))); + math_ATan2($3, + $5)); } | T_OP_STRCMP '(' string comma string ')' { @@ -1339,92 +1335,23 @@ relocconst : T_ID uconst : const { - int32_t value = constexpr_GetConstantValue(&$1); + int32_t value = $1; if (value < 0) fatalerror("Constant mustn't be negative: %d", value); $$ = value; } ; -const : T_ID { constexpr_Symbol(&$$, $1); } - | T_NUMBER { constexpr_Number(&$$, $1); } - | T_OP_HIGH '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); } - | T_OP_LOW '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); } - | T_OP_BANK '(' T_ID ')' +const : relocconst { - constexpr_BankSymbol(&$$, $3); + if (!rpn_isKnown(&$1)) { + yyerror("Expected constant expression: %s", + $1.reason); + $$ = 0; + } else { + $$ = $1.nVal; + } } - | T_OP_BANK '(' string ')' - { - constexpr_BankSection(&$$, $3); - } - | string - { - char *s = $1; - int32_t length = charmap_Convert(&s); - constexpr_Number(&$$, str2int2(s, length)); - free(s); - } - | T_OP_LOGICNOT const %prec NEG { constexpr_UnaryOp(&$$, $1, &$2); } - | const T_OP_LOGICOR const { constexpr_BinaryOp(&$$, $2, &$1, &$3); } - | const T_OP_LOGICAND const { constexpr_BinaryOp(&$$, $2, &$1, &$3); } - | const T_OP_LOGICEQU const { constexpr_BinaryOp(&$$, $2, &$1, &$3); } - | const T_OP_LOGICGT const { constexpr_BinaryOp(&$$, $2, &$1, &$3); } - | const T_OP_LOGICLT const { constexpr_BinaryOp(&$$, $2, &$1, &$3); } - | const T_OP_LOGICGE const { constexpr_BinaryOp(&$$, $2, &$1, &$3); } - | const T_OP_LOGICLE const { constexpr_BinaryOp(&$$, $2, &$1, &$3); } - | const T_OP_LOGICNE const { constexpr_BinaryOp(&$$, $2, &$1, &$3); } - | const T_OP_ADD const { constexpr_BinaryOp(&$$, $2, &$1, &$3); } - | const T_OP_SUB const { constexpr_BinaryOp(&$$, $2, &$1, &$3); } - | const T_OP_XOR const { constexpr_BinaryOp(&$$, $2, &$1, &$3); } - | const T_OP_OR const { constexpr_BinaryOp(&$$, $2, &$1, &$3); } - | const T_OP_AND const { constexpr_BinaryOp(&$$, $2, &$1, &$3); } - | const T_OP_SHL const { constexpr_BinaryOp(&$$, $2, &$1, &$3); } - | const T_OP_SHR const { constexpr_BinaryOp(&$$, $2, &$1, &$3); } - | const T_OP_MUL const { constexpr_BinaryOp(&$$, $2, &$1, &$3); } - | const T_OP_DIV const { constexpr_BinaryOp(&$$, $2, &$1, &$3); } - | const T_OP_MOD const { constexpr_BinaryOp(&$$, $2, &$1, &$3); } - | T_OP_ADD const %prec NEG { constexpr_UnaryOp(&$$, $1, &$2); } - | T_OP_SUB const %prec NEG { constexpr_UnaryOp(&$$, $1, &$2); } - | T_OP_NOT const %prec NEG { constexpr_UnaryOp(&$$, $1, &$2); } - | T_OP_ROUND '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); } - | T_OP_CEIL '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); } - | T_OP_FLOOR '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); } - | T_OP_FDIV '(' const comma const ')' { constexpr_BinaryOp(&$$, $1, &$3, &$5); } - | T_OP_FMUL '(' const comma const ')' { constexpr_BinaryOp(&$$, $1, &$3, &$5); } - | T_OP_SIN '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); } - | T_OP_COS '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); } - | T_OP_TAN '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); } - | T_OP_ASIN '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); } - | T_OP_ACOS '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); } - | T_OP_ATAN '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); } - | T_OP_ATAN2 '(' const comma const ')' { constexpr_BinaryOp(&$$, $1, &$3, &$5); } - | T_OP_DEF { - oDontExpandStrings = true; - } '(' T_ID ')' - { - struct sSymbol const *sym = sym_FindSymbol($4); - if (sym && !(sym_IsDefined(sym) && sym->type != SYM_LABEL)) - yyerror("Label \"%s\" is not a valid argument to DEF", - $4); - constexpr_Number(&$$, !!sym); - oDontExpandStrings = false; - } - | T_OP_STRCMP '(' string comma string ')' - { - constexpr_Number(&$$, strcmp($3, $5)); - } - | T_OP_STRIN '(' string comma string ')' - { - char *p = strstr($3, $5); - - if (p != NULL) - constexpr_Number(&$$, p - $3 + 1); - else - constexpr_Number(&$$, 0); - } - | T_OP_STRLEN '(' string ')' { constexpr_Number(&$$, strlenUTF8($3)); } - | '(' const ')' { $$ = $2; } ; string : T_STRING @@ -1769,7 +1696,7 @@ z80_ldio : T_Z80_LDIO T_MODE_A comma op_mem_ind { rpn_CheckHRAM(&$4, &$4); - if ((!rpn_isReloc(&$4)) && ($4.nVal < 0 || ($4.nVal > 0xFF && $4.nVal < 0xFF00) || $4.nVal > 0xFFFF)) + if ((rpn_isKnown(&$4)) && ($4.nVal < 0 || ($4.nVal > 0xFF && $4.nVal < 0xFF00) || $4.nVal > 0xFFFF)) yyerror("Source address $%x not in $FF00 to $FFFF", $4.nVal); out_AbsByte(0xF0); @@ -1780,7 +1707,7 @@ z80_ldio : T_Z80_LDIO T_MODE_A comma op_mem_ind { rpn_CheckHRAM(&$2, &$2); - if ((!rpn_isReloc(&$2)) && ($2.nVal < 0 || ($2.nVal > 0xFF && $2.nVal < 0xFF00) || $2.nVal > 0xFFFF)) + if ((rpn_isKnown(&$2)) && ($2.nVal < 0 || ($2.nVal > 0xFF && $2.nVal < 0xFF00) || $2.nVal > 0xFFFF)) yyerror("Destination address $%x not in $FF00 to $FFFF", $2.nVal); out_AbsByte(0xE0); @@ -1844,7 +1771,7 @@ z80_ld_mem : T_Z80_LD op_mem_ind comma T_MODE_SP | T_Z80_LD op_mem_ind comma T_MODE_A { if (CurrentOptions.optimizeloads && - (!rpn_isReloc(&$2)) && ($2.nVal >= 0xFF00)) { + (rpn_isKnown(&$2)) && ($2.nVal >= 0xFF00)) { out_AbsByte(0xE0); out_AbsByte($2.nVal & 0xFF); rpn_Free(&$2); @@ -1899,7 +1826,7 @@ z80_ld_a : T_Z80_LD reg_r comma T_MODE_C_IND { if ($2 == REG_A) { if (CurrentOptions.optimizeloads && - (!rpn_isReloc(&$4)) && ($4.nVal >= 0xFF00)) { + (rpn_isKnown(&$4)) && ($4.nVal >= 0xFF00)) { out_AbsByte(0xF0); out_AbsByte($4.nVal & 0xFF); rpn_Free(&$4); @@ -2036,13 +1963,14 @@ z80_rrca : T_Z80_RRCA z80_rst : T_Z80_RST const_8bit { - if (rpn_isReloc(&$2)) { + if (!rpn_isKnown(&$2)) { rpn_CheckRST(&$2, &$2); out_RelByte(&$2); - } else if (($2.nVal & 0x38) != $2.nVal) + } else if (($2.nVal & 0x38) != $2.nVal) { yyerror("Invalid address $%x for RST", $2.nVal); - else + } else { out_AbsByte(0xC7 | $2.nVal); + } rpn_Free(&$2); } ; diff --git a/src/asm/constexpr.c b/src/asm/constexpr.c deleted file mode 100644 index d4b323cc..00000000 --- a/src/asm/constexpr.c +++ /dev/null @@ -1,298 +0,0 @@ -/* - * This file is part of RGBDS. - * - * Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors. - * - * SPDX-License-Identifier: MIT - */ - -#include -#include -#include - -#include "asm/asm.h" -#include "asm/constexpr.h" -#include "asm/lexer.h" -#include "asm/main.h" -#include "asm/mymath.h" -#include "asm/output.h" -#include "asm/rpn.h" -#include "asm/symbol.h" -#include "asm/warning.h" - -#include "asmy.h" - -void constexpr_Symbol(struct ConstExpression *expr, char *tzSym) -{ - struct sSymbol *sym = sym_FindSymbol(tzSym); - - if (!sym) { - fatalerror("'%s' not defined", tzSym); - } else if (!sym_IsConstant(sym)) { - expr->u.pSym = sym; - expr->isSym = 1; - } else { - constexpr_Number(expr, sym_GetConstantValue(tzSym)); - } -} - -void constexpr_BankSymbol(struct ConstExpression *expr, char *tzSym) -{ - constexpr_Number(expr, 0); - struct sSymbol *sym = sym_FindSymbol(tzSym); - - if (!sym) { - yyerror("BANK argument doesn't exist"); - } else if (sym == pPCSymbol) { - if (pCurrentSection->nBank == -1) - yyerror("Current bank is not known yet"); - else - constexpr_Number(expr, pCurrentSection->nBank); - } else if (sym->type != SYM_LABEL) { - yyerror("BANK argument must be a label"); - } else if (sym->pSection->nBank == -1) { - yyerror("BANK argument's bank is not known yet'"); - } else { - constexpr_Number(expr, sym->pSection->nBank); - } -} - -void constexpr_BankSection(struct ConstExpression *expr, char *tzSectionName) -{ - constexpr_Number(expr, 0); - struct Section *pSection = out_FindSectionByName(tzSectionName); - - if (!pSection) - yyerror("Section \"%s\" doesn't exist", tzSectionName); - else if (pSection->nBank == -1) - yyerror("Section \"%s\"'s bank is not known yet", - tzSectionName); - else - constexpr_Number(expr, pSection->nBank); -} - -void constexpr_Number(struct ConstExpression *expr, int32_t i) -{ - expr->u.nVal = i; - expr->isSym = 0; -} - -void constexpr_UnaryOp(struct ConstExpression *expr, - int32_t op, - const struct ConstExpression *src) -{ - if (src->isSym) - fatalerror("Non-constant operand in constant expression"); - - int32_t value = src->u.nVal; - int32_t result = 0; - - switch (op) { - case T_OP_HIGH: - result = (value >> 8) & 0xFF; - break; - case T_OP_LOW: - result = value & 0xFF; - break; - case T_OP_LOGICNOT: - result = !value; - break; - case T_OP_ADD: - result = value; - break; - case T_OP_SUB: - result = -(uint32_t)value; - break; - case T_OP_NOT: - result = ~value; - break; - case T_OP_ROUND: - result = math_Round(value); - break; - case T_OP_CEIL: - result = math_Ceil(value); - break; - case T_OP_FLOOR: - result = math_Floor(value); - break; - case T_OP_SIN: - result = math_Sin(value); - break; - case T_OP_COS: - result = math_Cos(value); - break; - case T_OP_TAN: - result = math_Tan(value); - break; - case T_OP_ASIN: - result = math_ASin(value); - break; - case T_OP_ACOS: - result = math_ACos(value); - break; - case T_OP_ATAN: - result = math_ATan(value); - break; - default: - fatalerror("Unknown unary op"); - } - - constexpr_Number(expr, result); -} - -void constexpr_BinaryOp(struct ConstExpression *expr, - int32_t op, - const struct ConstExpression *src1, - const struct ConstExpression *src2) -{ - int32_t value1; - int32_t value2; - int32_t result = 0; - - if (op == T_OP_SUB && src1->isSym && src2->isSym) { - char *symName1 = src1->u.pSym->tzName; - char *symName2 = src2->u.pSym->tzName; - - if (!sym_IsRelocDiffDefined(symName1, symName2)) - fatalerror("'%s - %s' not defined", symName1, symName2); - value1 = sym_GetDefinedValue(symName1); - value2 = sym_GetDefinedValue(symName2); - result = value1 - value2; - } else if (src1->isSym || src2->isSym) { - fatalerror("Non-constant operand in constant expression"); - } else { - value1 = src1->u.nVal; - value2 = src2->u.nVal; - - switch (op) { - case T_OP_LOGICOR: - result = value1 || value2; - break; - case T_OP_LOGICAND: - result = value1 && value2; - break; - case T_OP_LOGICEQU: - result = value1 == value2; - break; - case T_OP_LOGICGT: - result = value1 > value2; - break; - case T_OP_LOGICLT: - result = value1 < value2; - break; - case T_OP_LOGICGE: - result = value1 >= value2; - break; - case T_OP_LOGICLE: - result = value1 <= value2; - break; - case T_OP_LOGICNE: - result = value1 != value2; - break; - case T_OP_ADD: - result = (uint32_t)value1 + (uint32_t)value2; - break; - case T_OP_SUB: - result = (uint32_t)value1 - (uint32_t)value2; - break; - case T_OP_XOR: - result = value1 ^ value2; - break; - case T_OP_OR: - result = value1 | value2; - break; - case T_OP_AND: - result = value1 & value2; - break; - case T_OP_SHL: - case T_OP_SHR: - if (value2 < 0) - warning(WARNING_SHIFT_AMOUNT, "Shifting %s by negative amount %d", - op == T_OP_SHL ? "left" : "right", - value2); - if (op == T_OP_SHR) { - value2 = -value2; /* Right shift == neg left */ - - if (value1 < 0) - warning(WARNING_SHIFT, "Shifting negative value %d", - value1); - } - - if (value2 >= 0) { - // Shift left - if (value2 >= 32) { - warning(WARNING_SHIFT_AMOUNT, "Shifting left by large amount %d", - value2); - result = 0; - } else { - /* - * Use unsigned to force a bitwise shift - * Casting back is OK because the types - * implement two's complement behavior - */ - result = (uint32_t)value1 << value2; - } - } else { - // Shift right - value2 = -value2; - if (value2 >= 32) { - warning(WARNING_SHIFT_AMOUNT, "Shifting right by large amount %d", - value2); - result = value1 < 0 ? -1 : 0; - } else if (value1 >= 0) { - result = value1 >> value2; - } else { - /* - * The C standard leaves shifting right - * negative values undefined, so use a - * left shift manually sign-extended - */ - result = (uint32_t)value1 >> value2 | - -((uint32_t)1 << (32 - value2)); - } - } - break; - case T_OP_MUL: - result = (uint32_t)value1 * (uint32_t)value2; - break; - case T_OP_DIV: - if (value2 == 0) - fatalerror("Division by zero"); - if (value1 == INT32_MIN && value2 == -1) { - warning(WARNING_DIV, "Division of min value by -1"); - result = INT32_MIN; - } else { - result = value1 / value2; - } - break; - case T_OP_MOD: - if (value2 == 0) - fatalerror("Division by zero"); - if (value1 == INT32_MIN && value2 == -1) - result = 0; - else - result = value1 % value2; - break; - case T_OP_FDIV: - result = math_Div(value1, value2); - break; - case T_OP_FMUL: - result = math_Mul(value1, value2); - break; - case T_OP_ATAN2: - result = math_ATan2(value1, value2); - break; - default: - fatalerror("Unknown binary op"); - } - } - - constexpr_Number(expr, result); -} - -int32_t constexpr_GetConstantValue(struct ConstExpression *expr) -{ - if (expr->isSym) - fatalerror("Non-constant expression"); - return expr->u.nVal; -} diff --git a/src/asm/globlex.c b/src/asm/globlex.c index e591cd1a..44881a96 100644 --- a/src/asm/globlex.c +++ b/src/asm/globlex.c @@ -14,7 +14,6 @@ #include #include "asm/asm.h" -#include "asm/constexpr.h" #include "asm/lexer.h" #include "asm/main.h" #include "asm/rpn.h" diff --git a/src/asm/lexer.c b/src/asm/lexer.c index 6d457901..23e00e0c 100644 --- a/src/asm/lexer.c +++ b/src/asm/lexer.c @@ -15,7 +15,6 @@ #include #include "asm/asm.h" -#include "asm/constexpr.h" #include "asm/fstack.h" #include "asm/lexer.h" #include "asm/main.h" diff --git a/src/asm/output.c b/src/asm/output.c index e8d08cba..d616e11e 100644 --- a/src/asm/output.c +++ b/src/asm/output.c @@ -800,7 +800,7 @@ void out_RelByte(struct Expression *expr) { checkcodesection(); checksectionoverflow(1); - if (rpn_isReloc(expr)) { + if (!rpn_isKnown(expr)) { pCurrentSection->tData[nPC] = 0; createpatch(PATCHTYPE_BYTE, expr); pCurrentSection->nPC++; @@ -835,7 +835,7 @@ void out_RelWord(struct Expression *expr) { checkcodesection(); checksectionoverflow(2); - if (rpn_isReloc(expr)) { + if (!rpn_isKnown(expr)) { pCurrentSection->tData[nPC] = 0; pCurrentSection->tData[nPC + 1] = 0; createpatch(PATCHTYPE_WORD, expr); @@ -872,7 +872,7 @@ void out_RelLong(struct Expression *expr) { checkcodesection(); checksectionoverflow(4); - if (rpn_isReloc(expr)) { + if (!rpn_isKnown(expr)) { pCurrentSection->tData[nPC] = 0; pCurrentSection->tData[nPC + 1] = 0; pCurrentSection->tData[nPC + 2] = 0; @@ -895,14 +895,25 @@ void out_PCRelByte(struct Expression *expr) { checkcodesection(); checksectionoverflow(1); + if (!rpn_isKnown(expr) || pCurrentSection->nOrg == -1) { + pCurrentSection->tData[nPC] = 0; + createpatch(PATCHTYPE_JR, expr); + pCurrentSection->nPC++; + nPC++; + pPCSymbol->nValue++; + } else { + /* Target is relative to the byte *after* the operand */ + uint16_t address = pCurrentSection->nOrg + nPC + 1; + /* The offset wraps (jump from ROM to HRAM, for loopexample) */ + int16_t offset = expr->nVal - address; - /* Always let the linker calculate the offset. */ - pCurrentSection->tData[nPC] = 0; - createpatch(PATCHTYPE_JR, expr); - pCurrentSection->nPC++; - nPC++; - pPCSymbol->nValue++; - + if (offset < -128 || offset > 127) { + yyerror("jr target out of reach (expected -129 < %d < 128)", offset); + out_AbsByte(0); + } else { + out_AbsByte(offset); + } + } rpn_Free(expr); } diff --git a/src/asm/rpn.c b/src/asm/rpn.c index 53e31956..aceed207 100644 --- a/src/asm/rpn.c +++ b/src/asm/rpn.c @@ -11,6 +11,7 @@ */ #include +#include #include #include #include @@ -22,67 +23,50 @@ #include "asm/output.h" #include "asm/warning.h" -#include "linkdefs.h" +/* Makes an expression "not known", also setting its error message */ +#define makeUnknown(expr_, ...) do { \ + struct Expression *_expr = expr_; \ + _expr->isKnown = false; \ + /* If we had `asprintf` this would be great, but alas. */ \ + _expr->reason = malloc(128); /* Use an initial reasonable size */ \ + if (!_expr->reason) \ + fatalerror("Can't allocate err string: %s", strerror(errno)); \ + int size = snprintf(_expr->reason, 128, __VA_ARGS__); \ + if (size >= 128) { /* If this wasn't enough, try again */ \ + _expr->reason = realloc(_expr->reason, size + 1); \ + sprintf(_expr->reason, __VA_ARGS__); \ + } \ +} while (0) -void mergetwoexpressions(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2) +static uint8_t *reserveSpace(struct Expression *expr, uint32_t size) { - assert(src1->tRPN != NULL && src2->tRPN != NULL); - - if (src1->nRPNLength + src2->nRPNLength > MAXRPNLEN) - fatalerror("RPN expression is too large"); - - uint32_t len = src1->nRPNLength + src2->nRPNLength; - - expr->nVal = 0; - expr->tRPN = src1->tRPN; - - if (src1->nRPNCapacity >= len) { - expr->nRPNCapacity = src1->nRPNCapacity; - } else { - uint32_t cap1 = src1->nRPNCapacity; - uint32_t cap2 = src2->nRPNCapacity; - uint32_t cap = (cap1 > cap2) ? cap1 : cap2; - - if (len > cap) - cap = (cap <= MAXRPNLEN / 2) ? cap * 2 : MAXRPNLEN; - - expr->nRPNCapacity = cap; - expr->tRPN = realloc(expr->tRPN, expr->nRPNCapacity); - if (expr->tRPN == NULL) - fatalerror("No memory for RPN expression"); - } - - memcpy(expr->tRPN + src1->nRPNLength, src2->tRPN, src2->nRPNLength); - free(src2->tRPN); - - expr->nRPNLength = len; - expr->nRPNPatchSize = src1->nRPNPatchSize + src2->nRPNPatchSize; - expr->nRPNOut = 0; - expr->isReloc = src1->isReloc || src2->isReloc; -} - -/* - * Add a byte to the RPN expression - */ -void pushbyte(struct Expression *expr, uint8_t b) -{ - if (expr->nRPNLength == expr->nRPNCapacity) { - if (expr->nRPNCapacity == 0) - expr->nRPNCapacity = 256; - else if (expr->nRPNCapacity == MAXRPNLEN) - fatalerror("RPN expression is too large"); + /* This assumes the RPN length is always less than the capacity */ + if (expr->nRPNCapacity - expr->nRPNLength < size) { + /* If there isn't enough room to reserve the space, realloc */ + if (!expr->tRPN) + expr->nRPNCapacity = 256; /* Initial size */ + else if (expr->nRPNCapacity >= MAXRPNLEN) + /* + * To avoid generating humongous object files, cap the + * size of RPN expressions + */ + fatalerror("RPN expression cannot grow larger than %d bytes", + MAXRPNLEN); else if (expr->nRPNCapacity > MAXRPNLEN / 2) expr->nRPNCapacity = MAXRPNLEN; else expr->nRPNCapacity *= 2; expr->tRPN = realloc(expr->tRPN, expr->nRPNCapacity); - if (expr->tRPN == NULL) - fatalerror("No memory for RPN expression"); + if (!expr->tRPN) + fatalerror("Failed to grow RPN expression: %s", + strerror(errno)); } - expr->tRPN[expr->nRPNLength++] = b; + uint8_t *ptr = expr->tRPN + expr->nRPNLength; + + expr->nRPNLength += size; + return ptr; } /* @@ -90,12 +74,14 @@ void pushbyte(struct Expression *expr, uint8_t b) */ void rpn_Init(struct Expression *expr) { + expr->reason = NULL; + expr->isKnown = true; + expr->isSymbol = false; expr->tRPN = NULL; expr->nRPNCapacity = 0; expr->nRPNLength = 0; expr->nRPNPatchSize = 0; expr->nRPNOut = 0; - expr->isReloc = 0; } /* @@ -104,6 +90,7 @@ void rpn_Init(struct Expression *expr) void rpn_Free(struct Expression *expr) { free(expr->tRPN); + free(expr->reason); rpn_Init(expr); } @@ -119,11 +106,19 @@ uint16_t rpn_PopByte(struct Expression *expr) } /* - * Determine if the current expression is relocatable + * Determine if the current expression is known at assembly time */ -uint32_t rpn_isReloc(const struct Expression *expr) +bool rpn_isKnown(const struct Expression *expr) { - return expr->isReloc; + return expr->isKnown; +} + +/* + * Determine if the current expression is a symbol suitable for const diffing + */ +bool rpn_isSymbol(const struct Expression *expr) +{ + return expr->isSymbol; } /* @@ -132,13 +127,7 @@ uint32_t rpn_isReloc(const struct Expression *expr) void rpn_Number(struct Expression *expr, uint32_t i) { rpn_Init(expr); - pushbyte(expr, RPN_CONST); - pushbyte(expr, i); - pushbyte(expr, i >> 8); - pushbyte(expr, i >> 16); - pushbyte(expr, i >> 24); expr->nVal = i; - expr->nRPNPatchSize += 5; } void rpn_Symbol(struct Expression *expr, char *tzSym) @@ -147,20 +136,28 @@ void rpn_Symbol(struct Expression *expr, char *tzSym) if (!sym || !sym_IsConstant(sym)) { rpn_Init(expr); + expr->isSymbol = true; + sym_Ref(tzSym); - expr->isReloc = 1; - pushbyte(expr, RPN_SYM); - while (*tzSym) - pushbyte(expr, *tzSym++); - pushbyte(expr, 0); - expr->nRPNPatchSize += 5; + makeUnknown(expr, strcmp(tzSym, "@") + ? "'%s' is not constant at assembly time" + : "PC is not constant at assembly time", + tzSym); + expr->nRPNPatchSize += 5; /* 1-byte opcode + 4-byte symbol ID */ + + size_t nameLen = strlen(tzSym) + 1; /* Don't forget NUL! */ + uint8_t *ptr = reserveSpace(expr, nameLen + 1); + *ptr++ = RPN_SYM; + memcpy(ptr, tzSym, nameLen); /* RGBLINK assumes PC is at the byte being computed... */ if (sym == pPCSymbol && nPCOffset) { struct Expression pc = *expr, offset; rpn_Number(&offset, nPCOffset); - rpn_SUB(expr, &pc, &offset); + rpn_BinaryOp(RPN_SUB, expr, &pc, &offset); + if (!rpn_isKnown(expr)) + expr->isSymbol = true; } } else { rpn_Number(expr, sym_GetConstantValue(tzSym)); @@ -171,17 +168,13 @@ void rpn_BankSelf(struct Expression *expr) { rpn_Init(expr); - if (pCurrentSection->nBank == -1) - /* - * This is not really relocatable, but this makes the assembler - * write this expression as a RPN patch to the object file. - */ - expr->isReloc = 1; - else + if (pCurrentSection->nBank == -1) { + makeUnknown(expr, "Current section's bank is not known"); + expr->nRPNPatchSize++; + *reserveSpace(expr, 1) = RPN_BANK_SELF; + } else { expr->nVal = pCurrentSection->nBank; - - pushbyte(expr, RPN_BANK_SELF); - expr->nRPNPatchSize++; + } } void rpn_BankSymbol(struct Expression *expr, char *tzSym) @@ -194,25 +187,26 @@ void rpn_BankSymbol(struct Expression *expr, char *tzSym) return; } + rpn_Init(expr); if (sym && sym_IsConstant(sym)) { yyerror("BANK argument must be a relocatable identifier"); } else { - rpn_Init(expr); sym_Ref(tzSym); - pushbyte(expr, RPN_BANK_SYM); - for (unsigned int i = 0; tzSym[i]; i++) - pushbyte(expr, tzSym[i]); - pushbyte(expr, 0); - expr->nRPNPatchSize += 5; - /* If the symbol didn't exist, `sym_Ref` created it */ struct sSymbol *pSymbol = sym_FindSymbol(tzSym); - if (pSymbol->pSection && pSymbol->pSection->nBank != -1) - /* Symbol's section is known and bank's fixed */ + if (pSymbol->pSection && pSymbol->pSection->nBank != -1) { + /* Symbol's section is known and bank is fixed */ expr->nVal = pSymbol->pSection->nBank; - else - expr->isReloc = 1; + } else { + makeUnknown(expr, "\"%s\"'s bank is not known", tzSym); + expr->nRPNPatchSize += 5; /* opcode + 4-byte sect ID */ + + size_t nameLen = strlen(tzSym) + 1; /* Room for NUL! */ + uint8_t *ptr = reserveSpace(expr, nameLen + 1); + *ptr++ = RPN_BANK_SYM; + memcpy(ptr, tzSym, nameLen); + } } } @@ -222,213 +216,61 @@ void rpn_BankSection(struct Expression *expr, char *tzSectionName) struct Section *pSection = out_FindSectionByName(tzSectionName); - if (pSection && pSection->nBank != -1) + if (pSection && pSection->nBank != -1) { expr->nVal = pSection->nBank; - else - /* - * This is not really relocatable, but this makes the assembler - * write this expression as a RPN patch to the object file. - */ - expr->isReloc = 1; + } else { + makeUnknown(expr, "Section \"%s\"'s bank is not known", + tzSectionName); - pushbyte(expr, RPN_BANK_SECT); - expr->nRPNPatchSize++; + size_t nameLen = strlen(tzSectionName) + 1; /* Room for NUL! */ + uint8_t *ptr = reserveSpace(expr, nameLen + 1); - while (*tzSectionName) { - pushbyte(expr, *tzSectionName++); - expr->nRPNPatchSize++; + expr->nRPNPatchSize += nameLen + 1; + *ptr++ = RPN_BANK_SECT; + memcpy(ptr, tzSectionName, nameLen); } - - pushbyte(expr, 0); - expr->nRPNPatchSize++; } void rpn_CheckHRAM(struct Expression *expr, const struct Expression *src) { *expr = *src; - pushbyte(expr, RPN_HRAM); - expr->nRPNPatchSize++; + expr->isSymbol = false; + + if (rpn_isKnown(expr)) { + /* TODO */ + } else { + expr->nRPNPatchSize++; + *reserveSpace(expr, 1) = RPN_HRAM; + } } void rpn_CheckRST(struct Expression *expr, const struct Expression *src) { *expr = *src; - pushbyte(expr, RPN_RST); - expr->nRPNPatchSize++; + + if (rpn_isKnown(expr)) { + /* TODO */ + } else { + expr->nRPNPatchSize++; + *reserveSpace(expr, 1) = RPN_RST; + } } void rpn_LOGNOT(struct Expression *expr, const struct Expression *src) { *expr = *src; - expr->nVal = !expr->nVal; - pushbyte(expr, RPN_LOGUNNOT); - expr->nRPNPatchSize++; -} + expr->isSymbol = false; -void rpn_LOGOR(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2) -{ - mergetwoexpressions(expr, src1, src2); - expr->nVal = (src1->nVal || src2->nVal); - pushbyte(expr, RPN_LOGOR); - expr->nRPNPatchSize++; -} - -void rpn_LOGAND(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2) -{ - mergetwoexpressions(expr, src1, src2); - expr->nVal = (src1->nVal && src2->nVal); - pushbyte(expr, RPN_LOGAND); - expr->nRPNPatchSize++; -} - -void rpn_HIGH(struct Expression *expr, const struct Expression *src) -{ - *expr = *src; - - expr->nVal = (expr->nVal >> 8) & 0xFF; - - pushbyte(expr, RPN_CONST); - pushbyte(expr, 8); - pushbyte(expr, 0); - pushbyte(expr, 0); - pushbyte(expr, 0); - - pushbyte(expr, RPN_SHR); - - pushbyte(expr, RPN_CONST); - pushbyte(expr, 0xFF); - pushbyte(expr, 0); - pushbyte(expr, 0); - pushbyte(expr, 0); - - pushbyte(expr, RPN_AND); - - expr->nRPNPatchSize += 12; -} - -void rpn_LOW(struct Expression *expr, const struct Expression *src) -{ - *expr = *src; - - expr->nVal = expr->nVal & 0xFF; - - pushbyte(expr, RPN_CONST); - pushbyte(expr, 0xFF); - pushbyte(expr, 0); - pushbyte(expr, 0); - pushbyte(expr, 0); - - pushbyte(expr, RPN_AND); - - expr->nRPNPatchSize += 6; -} - -void rpn_LOGEQU(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2) -{ - mergetwoexpressions(expr, src1, src2); - expr->nVal = (src1->nVal == src2->nVal); - pushbyte(expr, RPN_LOGEQ); - expr->nRPNPatchSize++; -} - -void rpn_LOGGT(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2) -{ - mergetwoexpressions(expr, src1, src2); - expr->nVal = (src1->nVal > src2->nVal); - pushbyte(expr, RPN_LOGGT); - expr->nRPNPatchSize++; -} - -void rpn_LOGLT(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2) -{ - mergetwoexpressions(expr, src1, src2); - expr->nVal = (src1->nVal < src2->nVal); - pushbyte(expr, RPN_LOGLT); - expr->nRPNPatchSize++; -} - -void rpn_LOGGE(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2) -{ - mergetwoexpressions(expr, src1, src2); - expr->nVal = (src1->nVal >= src2->nVal); - pushbyte(expr, RPN_LOGGE); - expr->nRPNPatchSize++; -} - -void rpn_LOGLE(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2) -{ - mergetwoexpressions(expr, src1, src2); - expr->nVal = (src1->nVal <= src2->nVal); - pushbyte(expr, RPN_LOGLE); - expr->nRPNPatchSize++; -} - -void rpn_LOGNE(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2) -{ - mergetwoexpressions(expr, src1, src2); - expr->nVal = (src1->nVal != src2->nVal); - pushbyte(expr, RPN_LOGNE); - expr->nRPNPatchSize++; -} - -void rpn_ADD(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2) -{ - mergetwoexpressions(expr, src1, src2); - expr->nVal = ((uint32_t)src1->nVal + (uint32_t)src2->nVal); - pushbyte(expr, RPN_ADD); - expr->nRPNPatchSize++; -} - -void rpn_SUB(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2) -{ - mergetwoexpressions(expr, src1, src2); - expr->nVal = ((uint32_t)src1->nVal - (uint32_t)src2->nVal); - pushbyte(expr, RPN_SUB); - expr->nRPNPatchSize++; -} - -void rpn_XOR(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2) -{ - mergetwoexpressions(expr, src1, src2); - expr->nVal = (src1->nVal ^ src2->nVal); - pushbyte(expr, RPN_XOR); - expr->nRPNPatchSize++; -} - -void rpn_OR(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2) -{ - mergetwoexpressions(expr, src1, src2); - expr->nVal = (src1->nVal | src2->nVal); - pushbyte(expr, RPN_OR); - expr->nRPNPatchSize++; -} - -void rpn_AND(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2) -{ - mergetwoexpressions(expr, src1, src2); - expr->nVal = (src1->nVal & src2->nVal); - pushbyte(expr, RPN_AND); - expr->nRPNPatchSize++; + if (rpn_isKnown(expr)) { + expr->nVal = !expr->nVal; + } else { + expr->nRPNPatchSize++; + *reserveSpace(expr, 1) = RPN_LOGUNNOT; + } } static int32_t shift(int32_t shiftee, int32_t amount) { - if (shiftee < 0) - warning(WARNING_SHIFT, "Shifting negative value %d", shiftee); - if (amount >= 0) { // Left shift if (amount >= 32) { @@ -466,101 +308,247 @@ static int32_t shift(int32_t shiftee, int32_t amount) } } -void rpn_SHL(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2) +static struct sSymbol const *symbolOf(struct Expression const *expr) { - mergetwoexpressions(expr, src1, src2); - - if (!expr->isReloc) { - if (src2->nVal < 0) - warning(WARNING_SHIFT_AMOUNT, "Shifting left by negative value: %d", - src2->nVal); - - expr->nVal = shift(src1->nVal, src2->nVal); - } - - pushbyte(expr, RPN_SHL); - expr->nRPNPatchSize++; + if (!rpn_isSymbol(expr)) + return NULL; + return sym_FindSymbol((char *)expr->tRPN + 1); } -void rpn_SHR(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2) +static bool isDiffConstant(struct Expression const *src1, + struct Expression const *src2) { - mergetwoexpressions(expr, src1, src2); + /* Check if both expressions only refer to a single symbol */ + struct sSymbol const *symbol1 = symbolOf(src1); + struct sSymbol const *symbol2 = symbolOf(src2); - if (!expr->isReloc) { - if (src2->nVal < 0) - warning(WARNING_SHIFT_AMOUNT, "Shifting right by negative value: %d", - src2->nVal); + if (!symbol1 || !symbol2 + || symbol1->type != SYM_LABEL || symbol2->type != SYM_LABEL) + return false; - expr->nVal = shift(src1->nVal, -src2->nVal); - } - - pushbyte(expr, RPN_SHR); - expr->nRPNPatchSize++; + return symbol1->pSection == symbol2->pSection; } -void rpn_MUL(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2) +void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr, + const struct Expression *src1, const struct Expression *src2) { - mergetwoexpressions(expr, src1, src2); - expr->nVal = ((uint32_t)src1->nVal * (uint32_t)src2->nVal); - pushbyte(expr, RPN_MUL); - expr->nRPNPatchSize++; -} + expr->isSymbol = false; -void rpn_DIV(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2) -{ - mergetwoexpressions(expr, src1, src2); + /* First, check if the expression is known */ + expr->isKnown = src1->isKnown && src2->isKnown; + if (expr->isKnown) { + rpn_Init(expr); /* Init the expression to something sane */ - if (!expr->isReloc) { - if (src2->nVal == 0) - fatalerror("Division by zero"); + /* If both expressions are known, just compute the value */ + uint32_t uleft = src1->nVal, uright = src2->nVal; - if (src1->nVal == INT32_MIN && src2->nVal == -1) { - warning(WARNING_DIV, "Division of min value by -1"); - expr->nVal = INT32_MIN; - } else { - expr->nVal = (src1->nVal / src2->nVal); + switch (op) { + case RPN_LOGOR: + expr->nVal = src1->nVal || src2->nVal; + break; + case RPN_LOGAND: + expr->nVal = src1->nVal && src2->nVal; + break; + case RPN_LOGEQ: + expr->nVal = src1->nVal == src2->nVal; + break; + case RPN_LOGGT: + expr->nVal = src1->nVal > src2->nVal; + break; + case RPN_LOGLT: + expr->nVal = src1->nVal < src2->nVal; + break; + case RPN_LOGGE: + expr->nVal = src1->nVal >= src2->nVal; + break; + case RPN_LOGLE: + expr->nVal = src1->nVal <= src2->nVal; + break; + case RPN_LOGNE: + expr->nVal = src1->nVal != src2->nVal; + break; + case RPN_ADD: + expr->nVal = uleft + uright; + break; + case RPN_SUB: + expr->nVal = uleft - uright; + break; + case RPN_XOR: + expr->nVal = src1->nVal ^ src2->nVal; + break; + case RPN_OR: + expr->nVal = src1->nVal | src2->nVal; + break; + case RPN_AND: + expr->nVal = src1->nVal & src2->nVal; + break; + case RPN_SHL: + if (src2->nVal < 0) + warning(WARNING_SHIFT_AMOUNT, "Shifting left by negative amount %d", + src2->nVal); + + expr->nVal = shift(src1->nVal, src2->nVal); + break; + case RPN_SHR: + if (src1->nVal < 0) + warning(WARNING_SHIFT, "Shifting negative value %d", + src1->nVal); + + if (src2->nVal < 0) + warning(WARNING_SHIFT_AMOUNT, "Shifting right by negative amount %d", + src2->nVal); + + expr->nVal = shift(src1->nVal, -src2->nVal); + break; + case RPN_MUL: + expr->nVal = uleft * uright; + break; + case RPN_DIV: + if (src2->nVal == 0) + fatalerror("Division by zero"); + + if (src1->nVal == INT32_MIN + && src2->nVal == -1) { + warning(WARNING_DIV, "Division of min value by -1"); + expr->nVal = INT32_MIN; + } else { + expr->nVal = src1->nVal / src2->nVal; + } + break; + case RPN_MOD: + if (src2->nVal == 0) + fatalerror("Division by zero"); + + if (src1->nVal == INT32_MIN && src2->nVal == -1) + expr->nVal = 0; + else + expr->nVal = src1->nVal % src2->nVal; + break; + + case RPN_UNSUB: + case RPN_UNNOT: + case RPN_LOGUNNOT: + case RPN_BANK_SYM: + case RPN_BANK_SECT: + case RPN_BANK_SELF: + case RPN_HRAM: + case RPN_RST: + case RPN_CONST: + case RPN_SYM: + fatalerror("%d is no binary operator", op); } - } - pushbyte(expr, RPN_DIV); - expr->nRPNPatchSize++; + } else if (op == RPN_SUB && isDiffConstant(src1, src2)) { + struct sSymbol const *symbol1 = symbolOf(src1); + struct sSymbol const *symbol2 = symbolOf(src2); + + expr->nVal = symbol1->nValue - symbol2->nValue; + expr->isKnown = true; + } else { + /* If it's not known, start computing the RPN expression */ + + /* Convert the left-hand expression if it's constant */ + if (src1->isKnown) { + uint32_t lval = src1->nVal; + uint8_t bytes[] = {RPN_CONST, lval, lval >> 8, + lval >> 16, lval >> 24}; + expr->nRPNPatchSize = sizeof(bytes); + expr->tRPN = NULL; + expr->nRPNCapacity = 0; + expr->nRPNLength = 0; + memcpy(reserveSpace(expr, sizeof(bytes)), bytes, + sizeof(bytes)); + + /* Use the other expression's un-const reason */ + expr->reason = src2->reason; + free(src1->reason); + } else { + /* Otherwise just reuse its RPN buffer */ + expr->nRPNPatchSize = src1->nRPNPatchSize; + expr->tRPN = src1->tRPN; + expr->nRPNCapacity = src1->nRPNCapacity; + expr->nRPNLength = src1->nRPNLength; + expr->reason = src1->reason; + free(src2->reason); + } + + /* Now, merge the right expression into the left one */ + uint8_t *ptr = src2->tRPN; /* Pointer to the right RPN */ + uint32_t len = src2->nRPNLength; /* Size of the right RPN */ + uint32_t patchSize = src2->nRPNPatchSize; + + /* If the right expression is constant, merge a shim instead */ + uint32_t rval = src2->nVal; + uint8_t bytes[] = {RPN_CONST, rval, rval >> 8, rval >> 16, + rval >> 24}; + if (src2->isKnown) { + ptr = bytes; + len = sizeof(bytes); + patchSize = sizeof(bytes); + } + /* Copy the right RPN and append the operator */ + uint8_t *buf = reserveSpace(expr, len + 1); + + memcpy(buf, ptr, len); + buf[len] = op; + + free(src2->tRPN); /* If there was none, this is `free(NULL)` */ + expr->nRPNPatchSize += patchSize + 1; + } } -void rpn_MOD(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2) +void rpn_HIGH(struct Expression *expr, const struct Expression *src) { - mergetwoexpressions(expr, src1, src2); + *expr = *src; + expr->isSymbol = false; - if (!expr->isReloc) { - if (src2->nVal == 0) - fatalerror("Division by zero"); - - if (src1->nVal == INT32_MIN && src2->nVal == -1) - expr->nVal = 0; - else - expr->nVal = (src1->nVal % src2->nVal); + if (rpn_isKnown(expr)) { + expr->nVal = (uint32_t)expr->nVal >> 8 & 0xFF; + } else { + uint8_t bytes[] = {RPN_CONST, 8, 0, 0, 0, RPN_SHR, + RPN_CONST, 0xFF, 0, 0, 0, RPN_AND}; + expr->nRPNPatchSize += sizeof(bytes); + memcpy(reserveSpace(expr, sizeof(bytes)), bytes, sizeof(bytes)); } +} - pushbyte(expr, RPN_MOD); - expr->nRPNPatchSize++; +void rpn_LOW(struct Expression *expr, const struct Expression *src) +{ + *expr = *src; + expr->isSymbol = false; + + if (rpn_isKnown(expr)) { + expr->nVal = expr->nVal & 0xFF; + } else { + uint8_t bytes[] = {RPN_CONST, 0xFF, 0, 0, 0, RPN_AND}; + + expr->nRPNPatchSize += sizeof(bytes); + memcpy(reserveSpace(expr, sizeof(bytes)), bytes, sizeof(bytes)); + } } void rpn_UNNEG(struct Expression *expr, const struct Expression *src) { *expr = *src; - expr->nVal = -(uint32_t)expr->nVal; - pushbyte(expr, RPN_UNSUB); - expr->nRPNPatchSize++; + expr->isSymbol = false; + + if (rpn_isKnown(expr)) { + expr->nVal = -(uint32_t)expr->nVal; + } else { + expr->nRPNPatchSize++; + *reserveSpace(expr, 1) = RPN_UNSUB; + } } void rpn_UNNOT(struct Expression *expr, const struct Expression *src) { *expr = *src; - expr->nVal = ~expr->nVal; - pushbyte(expr, RPN_UNNOT); - expr->nRPNPatchSize++; + expr->isSymbol = false; + + if (rpn_isKnown(expr)) { + expr->nVal = ~expr->nVal; + } else { + expr->nRPNPatchSize++; + *reserveSpace(expr, 1) = RPN_UNNOT; + } } diff --git a/src/asm/symbol.c b/src/asm/symbol.c index af9068f4..83452eb7 100644 --- a/src/asm/symbol.c +++ b/src/asm/symbol.c @@ -269,7 +269,7 @@ uint32_t sym_GetConstantValue(char const *s) if (sym_IsConstant(psym)) return getvaluefield(psym); - fatalerror("Expression must have a constant value"); + fatalerror("\"%s\" does not have a constant value", s); } yyerror("'%s' not defined", s); diff --git a/test/asm/bank.err b/test/asm/bank.err index 6623e217..9654dbce 100644 --- a/test/asm/bank.err +++ b/test/asm/bank.err @@ -1,9 +1,9 @@ ERROR: bank.asm(14) -> bank.asm::def_sect(8): - Section "ROMX_bad"'s bank is not known yet + Expected constant expression: Section "ROMX_bad"'s bank is not known ERROR: bank.asm(16) -> bank.asm::def_sect(8): - Section "VRAM_bad"'s bank is not known yet + Expected constant expression: Section "VRAM_bad"'s bank is not known ERROR: bank.asm(18) -> bank.asm::def_sect(8): - Section "SRAM_bad"'s bank is not known yet + Expected constant expression: Section "SRAM_bad"'s bank is not known ERROR: bank.asm(21) -> bank.asm::def_sect(8): - Section "WRAMX_bad"'s bank is not known yet + Expected constant expression: Section "WRAMX_bad"'s bank is not known error: Assembly aborted (4 errors)! diff --git a/test/asm/bracketed-symbols.err b/test/asm/bracketed-symbols.err index 14a9a9e6..b6c44e82 100644 --- a/test/asm/bracketed-symbols.err +++ b/test/asm/bracketed-symbols.err @@ -1,4 +1,4 @@ ERROR: bracketed-symbols.asm(16): Print types are only allowed for numbers ERROR: bracketed-symbols.asm(20): - Expression must have a constant value + "Label" does not have a constant value diff --git a/test/asm/label-diff.asm b/test/asm/label-diff.asm index c331d6e0..fa81e945 100644 --- a/test/asm/label-diff.asm +++ b/test/asm/label-diff.asm @@ -31,20 +31,22 @@ POPS ; Ensure we are in neither section ; Diffing two labels in the same SECTION as well print_diff Known2, Known ; Diffing a constant and a "floating" label cannot work -; ...And that causes a fatal error print_diff Constant, Known + print_diff Constant, Known ; Diffing a constant and a ref cannot work -; ...And that causes a fatal error print_diff Constant, Unknown + print_diff Constant, Unknown ; Diffing a floating label and a ref cannot work -; ...And that causes a fatal error print_diff Known, Unknown + print_diff Known, Unknown + ; Diffing two refs cannot work + print_diff Unknown, Unknown2 ; Now let's fiddle with PC SECTION "fixed PC", ROM0[420] ; Diffing a constant and PC should work print_diff Constant, @ ; Diffing a floating label and PC cannot work -; ...And that causes a fatal error print_diff Known, @ + print_diff Known, @ ; Diffinf a ref and PC cannot work -; ...And that causes a fatal error print_diff Unknown, @ + print_diff Unknown, @ ; Diffing PC and PC should work print_diff @, @ ; Diffing PC and a label from here should work @@ -53,11 +55,11 @@ LocalFixed: SECTION "Floating PC", ROM0 ; Diffing a constant and PC cannot work -; ...And that causes a fatal error print_diff Constant, @ + print_diff Constant, @ ; Diffing a floating label and PC cannot work -; ...And that causes a fatal error print_diff Known, @ + print_diff Known, @ ; Diffinf a ref and PC cannot work -; ...And that causes a fatal error print_diff Unknown, @ + print_diff Unknown, @ ; Diffing PC and PC should work print_diff @, @ ; Diffing PC and a label from here should work diff --git a/test/asm/label-diff.err b/test/asm/label-diff.err index e69de29b..f098b2bc 100644 --- a/test/asm/label-diff.err +++ b/test/asm/label-diff.err @@ -0,0 +1,37 @@ +ERROR: label-diff.asm(34) -> label-diff.asm::print_diff(20): + Expected constant expression: 'Known' is not constant at assembly time +ERROR: label-diff.asm(34) -> label-diff.asm::print_diff(22): + Expected constant expression: 'Known' is not constant at assembly time +ERROR: label-diff.asm(36) -> label-diff.asm::print_diff(20): + Expected constant expression: 'Unknown' is not constant at assembly time +ERROR: label-diff.asm(36) -> label-diff.asm::print_diff(22): + Expected constant expression: 'Unknown' is not constant at assembly time +ERROR: label-diff.asm(38) -> label-diff.asm::print_diff(20): + Expected constant expression: 'Known' is not constant at assembly time +ERROR: label-diff.asm(38) -> label-diff.asm::print_diff(22): + Expected constant expression: 'Unknown' is not constant at assembly time +ERROR: label-diff.asm(40) -> label-diff.asm::print_diff(20): + Expected constant expression: 'Unknown' is not constant at assembly time +ERROR: label-diff.asm(40) -> label-diff.asm::print_diff(22): + Expected constant expression: 'Unknown2' is not constant at assembly time +ERROR: label-diff.asm(47) -> label-diff.asm::print_diff(20): + Expected constant expression: 'Known' is not constant at assembly time +ERROR: label-diff.asm(47) -> label-diff.asm::print_diff(22): + Expected constant expression: 'Known' is not constant at assembly time +ERROR: label-diff.asm(49) -> label-diff.asm::print_diff(20): + Expected constant expression: 'Unknown' is not constant at assembly time +ERROR: label-diff.asm(49) -> label-diff.asm::print_diff(22): + Expected constant expression: 'Unknown' is not constant at assembly time +ERROR: label-diff.asm(58) -> label-diff.asm::print_diff(20): + Expected constant expression: PC is not constant at assembly time +ERROR: label-diff.asm(58) -> label-diff.asm::print_diff(22): + Expected constant expression: PC is not constant at assembly time +ERROR: label-diff.asm(60) -> label-diff.asm::print_diff(20): + Expected constant expression: 'Known' is not constant at assembly time +ERROR: label-diff.asm(60) -> label-diff.asm::print_diff(22): + Expected constant expression: PC is not constant at assembly time +ERROR: label-diff.asm(62) -> label-diff.asm::print_diff(20): + Expected constant expression: 'Unknown' is not constant at assembly time +ERROR: label-diff.asm(62) -> label-diff.asm::print_diff(22): + Expected constant expression: PC is not constant at assembly time +error: Assembly aborted (18 errors)! diff --git a/test/asm/label-diff.out b/test/asm/label-diff.out index 67533371..bb02119d 100644 --- a/test/asm/label-diff.out +++ b/test/asm/label-diff.out @@ -2,6 +2,14 @@ $FFFFFFE5 $1B $4 $FFFFFFFC +$0 +$0 +$0 +$0 +$0 +$0 +$0 +$0 $FFFFFE86 $17A $0 @@ -12,3 +20,13 @@ $0 $0 $0 $0 +$0 +$0 +$0 +$0 +$0 +$0 +$0 +$0 +$0 +$0 diff --git a/test/asm/overflow.err b/test/asm/overflow.err index 03071f3f..8ed2aa85 100644 --- a/test/asm/overflow.err +++ b/test/asm/overflow.err @@ -2,8 +2,6 @@ warning: overflow.asm(24): [-Wdiv] Division of min value by -1 warning: overflow.asm(25): [-Wdiv] Division of min value by -1 -warning: overflow.asm(35): [-Wshift] - Shifting negative value -1 warning: overflow.asm(39): [-Wlarge-constant] Integer constant '4294967296' is too large warning: overflow.asm(42): [-Wlarge-constant] diff --git a/test/asm/pc-bank.err b/test/asm/pc-bank.err index e81e10cf..3c165fb9 100644 --- a/test/asm/pc-bank.err +++ b/test/asm/pc-bank.err @@ -1,5 +1,5 @@ ERROR: pc-bank.asm(2): Source address $2a00 not in $FF00 to $FFFF ERROR: pc-bank.asm(11): - Current bank is not known yet + Expected constant expression: Current section's bank is not known error: Assembly aborted (2 errors)! diff --git a/test/asm/shift.err b/test/asm/shift.err index aea9476e..ba1c7543 100644 --- a/test/asm/shift.err +++ b/test/asm/shift.err @@ -6,18 +6,12 @@ warning: shift.asm(14) -> shift.asm::test(3): [-Wshift-amount] Shifting left by large amount 9001 warning: shift.asm(14) -> shift.asm::test(6): [-Wshift-amount] Shifting left by large amount 9001 -warning: shift.asm(15) -> shift.asm::test(3): [-Wshift] - Shifting negative value -1 -warning: shift.asm(16) -> shift.asm::test(3): [-Wshift] - Shifting negative value -1 warning: shift.asm(16) -> shift.asm::test(3): [-Wshift-amount] Shifting left by large amount 32 warning: shift.asm(16) -> shift.asm::test(6): [-Wshift-amount] Shifting left by large amount 32 warning: shift.asm(17) -> shift.asm::test(3): [-Wshift-amount] - Shifting left by negative value: -9001 -warning: shift.asm(17) -> shift.asm::test(3): [-Wshift] - Shifting negative value -1 + Shifting left by negative amount -9001 warning: shift.asm(17) -> shift.asm::test(3): [-Wshift-amount] Shifting right by large amount 9001 warning: shift.asm(17) -> shift.asm::test(6): [-Wshift-amount] @@ -52,15 +46,15 @@ warning: shift.asm(23) -> shift.asm::test(3): [-Wshift] Shifting negative value -4 warning: shift.asm(23) -> shift.asm::test(6): [-Wshift] Shifting negative value -4 -warning: shift.asm(24) -> shift.asm::test(3): [-Wshift-amount] - Shifting right by negative value: -9001 warning: shift.asm(24) -> shift.asm::test(3): [-Wshift] Shifting negative value -1 warning: shift.asm(24) -> shift.asm::test(3): [-Wshift-amount] - Shifting left by large amount 9001 -warning: shift.asm(24) -> shift.asm::test(6): [-Wshift-amount] Shifting right by negative amount -9001 +warning: shift.asm(24) -> shift.asm::test(3): [-Wshift-amount] + Shifting left by large amount 9001 warning: shift.asm(24) -> shift.asm::test(6): [-Wshift] Shifting negative value -1 +warning: shift.asm(24) -> shift.asm::test(6): [-Wshift-amount] + Shifting right by negative amount -9001 warning: shift.asm(24) -> shift.asm::test(6): [-Wshift-amount] Shifting left by large amount 9001