From 3d0dc5815329de351f72b75afe9f01184464ff3b Mon Sep 17 00:00:00 2001 From: acqn Date: Sat, 13 Jan 2024 00:46:14 +0800 Subject: [PATCH 01/16] Fixed visibility of undeclared functions and objects. --- src/cc65/compile.c | 23 +++++++++++------------ src/cc65/symtab.c | 30 +++++++++++++++++++++++------- src/cc65/symtab.h | 4 ++-- test/err/bug2304-var-use.c | 15 +++++++++++++++ test/misc/Makefile | 6 ++++++ test/misc/bug2304-implicit-func.c | 21 +++++++++++++++++++++ 6 files changed, 78 insertions(+), 21 deletions(-) create mode 100644 test/err/bug2304-var-use.c create mode 100644 test/misc/bug2304-implicit-func.c diff --git a/src/cc65/compile.c b/src/cc65/compile.c index 108c80a28..f14774658 100644 --- a/src/cc65/compile.c +++ b/src/cc65/compile.c @@ -163,19 +163,19 @@ static void Parse (void) break; } - /* Check if we must reserve storage for the variable. We do this, - ** - ** - if it is not a typedef or function, - ** - if we don't had a storage class given ("int i") - ** - if the storage class is explicitly specified as static, - ** - or if there is an initialization. - ** - ** This means that "extern int i;" will not get storage allocated - ** in this translation unit. - */ + /* The symbol is now visible in the file scope */ if ((Decl.StorageClass & SC_TYPEMASK) != SC_FUNC && (Decl.StorageClass & SC_TYPEMASK) != SC_TYPEDEF) { - /* The variable is visible in the file scope */ + /* Check if we must reserve storage for the variable. We do this, + ** + ** - if it is not a typedef or function, + ** - if we don't had a storage class given ("int i") + ** - if the storage class is explicitly specified as static, + ** - or if there is an initialization. + ** + ** This means that "extern int i;" will not get storage allocated + ** in this translation unit. + */ if ((Decl.StorageClass & SC_STORAGEMASK) == SC_NONE || (Decl.StorageClass & SC_STORAGEMASK) == SC_STATIC || ((Decl.StorageClass & SC_STORAGEMASK) == SC_EXTERN && @@ -189,7 +189,6 @@ static void Parse (void) ** or semicolon, it must be followed by a function body. */ if ((Decl.StorageClass & SC_TYPEMASK) == SC_FUNC) { - /* The function is now visible in the file scope */ if (CurTok.Tok == TOK_LCURLY) { /* A definition */ Decl.StorageClass |= SC_DEF; diff --git a/src/cc65/symtab.c b/src/cc65/symtab.c index a76e60450..69484456f 100644 --- a/src/cc65/symtab.c +++ b/src/cc65/symtab.c @@ -557,8 +557,10 @@ static SymEntry* FindSymInTable (const SymTable* T, const char* Name, unsigned H -static SymEntry* FindSymInTree (const SymTable* Tab, const char* Name) -/* Find the symbol with the given name in the table tree that starts with T */ +static SymEntry* FindVisibleSymInTree (const SymTable* Tab, const char* Name) +/* Find the visible symbol with the given name in the table tree that starts +** with Tab. +*/ { /* Get the hash over the name */ unsigned Hash = HashStr (Name); @@ -574,7 +576,7 @@ static SymEntry* FindSymInTree (const SymTable* Tab, const char* Name) } /* Bail out if we found it */ - if (E != 0) { + if (E != 0 && (Tab != SymTab0 || (E->Flags & SC_LOCALSCOPE) == 0)) { return E; } @@ -589,9 +591,9 @@ static SymEntry* FindSymInTree (const SymTable* Tab, const char* Name) SymEntry* FindSym (const char* Name) -/* Find the symbol with the given name */ +/* Find with the given name the symbol visible in the current scope */ { - return FindSymInTree (SymTab, Name); + return FindVisibleSymInTree (SymTab, Name); } @@ -613,9 +615,9 @@ SymEntry* FindLocalSym (const char* Name) SymEntry* FindTagSym (const char* Name) -/* Find the symbol with the given name in the tag table */ +/* Find with the given name the tag symbol visible in the current scope */ { - return FindSymInTree (TagTab, Name); + return FindVisibleSymInTree (TagTab, Name); } @@ -1356,6 +1358,13 @@ SymEntry* AddGlobalSym (const char* Name, const Type* T, unsigned Flags) Name); Entry = 0; } else if ((Flags & SC_TYPEMASK) != SC_TYPEDEF) { + /* If we are adding the symbol in the file scope, it is now + ** visible there. + */ + if (SymTab == SymTab0) { + Entry->Flags &= ~SC_LOCALSCOPE; + } + /* The C standard specifies that the result is undefined if the ** same thing has both internal and external linkage. Most ** compilers choose to either give an error at compile time, or @@ -1415,6 +1424,13 @@ SymEntry* AddGlobalSym (const char* Name, const Type* T, unsigned Flags) } if (Entry == 0) { + /* Hide the symbol in the file scope if we are declaring it in a + ** local scope. + */ + if (Tab == SymTab0 && SymTab != SymTab0) { + Flags |= SC_LOCALSCOPE; + } + /* Create a new entry */ Entry = NewSymEntry (Name, Flags); diff --git a/src/cc65/symtab.h b/src/cc65/symtab.h index 53b0df4eb..236bc090a 100644 --- a/src/cc65/symtab.h +++ b/src/cc65/symtab.h @@ -142,7 +142,7 @@ void LeaveStructLevel (void); SymEntry* FindSym (const char* Name); -/* Find the symbol with the given name */ +/* Find with the given name the symbol visible in the current scope */ SymEntry* FindGlobalSym (const char* Name); /* Find the symbol with the given name in the global symbol table only */ @@ -151,7 +151,7 @@ SymEntry* FindLocalSym (const char* Name); /* Find the symbol with the given name in the current symbol table only */ SymEntry* FindTagSym (const char* Name); -/* Find the symbol with the given name in the tag table */ +/* Find with the given name the tag symbol visible in the current scope */ SymEntry FindStructField (const Type* TypeArray, const char* Name); /* Find a struct/union field in the fields list. diff --git a/test/err/bug2304-var-use.c b/test/err/bug2304-var-use.c new file mode 100644 index 000000000..8a88405e2 --- /dev/null +++ b/test/err/bug2304-var-use.c @@ -0,0 +1,15 @@ +/* Bug 2304 - Visibility of objects/functions undeclared in file scope but 'extern'-declared in unrelated block scopes */ + +void f1(void) +{ + extern int a; +} + +/* 'a' is still invisible in the file scope */ + +int main(void) +{ + return a * 0; /* Usage of 'a' should be an error */ +} + +int a = 42; diff --git a/test/misc/Makefile b/test/misc/Makefile index 811f7f462..cfcae0530 100644 --- a/test/misc/Makefile +++ b/test/misc/Makefile @@ -133,6 +133,12 @@ $(WORKDIR)/goto.$1.$2.prg: goto.c $(ISEQUAL) | $(WORKDIR) $(CC65) -t sim$2 -$1 -o $$@ $$< 2>$(WORKDIR)/goto.$1.$2.out $(ISEQUAL) $(WORKDIR)/goto.$1.$2.out goto.ref +# this one requires failure with --std=c89, it fails with --std=cc65 due to +# stricter checks +$(WORKDIR)/bug2304-implicit-func.$1.$2.prg: bug2304-implicit-func.c | $(WORKDIR) + $(if $(QUIET),echo misc/bug2304-implicit-func.$1.$2.prg) + $(NOT) $(CC65) --standard c89 -t sim$2 -$1 -o $$@ $$< $(NULLERR) + # should not compile until 3-byte struct by value tests are re-enabled $(WORKDIR)/struct-by-value.$1.$2.prg: struct-by-value.c | $(WORKDIR) $(if $(QUIET),echo misc/struct-by-value.$1.$2.prg) diff --git a/test/misc/bug2304-implicit-func.c b/test/misc/bug2304-implicit-func.c new file mode 100644 index 000000000..f6b7450ff --- /dev/null +++ b/test/misc/bug2304-implicit-func.c @@ -0,0 +1,21 @@ +/* Bug 2304 - Visibility of objects/functions undeclared in file scope but 'extern'-declared in unrelated block scopes */ + +/* This one should fail even in C89 */ + +void f1(void) +{ + extern unsigned int f(); +} + +/* 'f' is still invisible in the file scope */ + +int main(void) +{ + f(); /* Should be a conflict since the implicit function type is incompatible */ + return 0; +} + +unsigned int f() +{ + return 42; +} From 0b06c34dfc89271a135c24573352715da1aaf187 Mon Sep 17 00:00:00 2001 From: acqn Date: Sun, 14 Jan 2024 00:08:41 +0800 Subject: [PATCH 02/16] Added primitive support for the ISO C99 inline feature as well as the __inline__ extension. No inlining is actually done but that part is not required by the standard. --- src/cc65/compile.c | 6 +- src/cc65/declare.c | 84 ++++++++++++++++++++++-- src/cc65/expr.c | 2 +- src/cc65/function.c | 6 ++ src/cc65/locals.c | 2 +- src/cc65/scanner.h | 1 + src/cc65/symentry.h | 4 ++ src/cc65/symtab.c | 12 +++- test/ref/Makefile | 1 + test/ref/bug1889-missing-identifier.cref | 2 +- test/ref/inline-error.c | 36 ++++++++++ test/ref/inline-error.cref | 20 ++++++ test/val/inline-func.c | 20 ++++++ 13 files changed, 184 insertions(+), 12 deletions(-) create mode 100644 test/ref/inline-error.c create mode 100644 test/ref/inline-error.cref create mode 100644 test/val/inline-func.c diff --git a/src/cc65/compile.c b/src/cc65/compile.c index 108c80a28..b24751b59 100644 --- a/src/cc65/compile.c +++ b/src/cc65/compile.c @@ -121,7 +121,7 @@ static void Parse (void) } /* Read the declaration specifier */ - ParseDeclSpec (&Spec, TS_DEFAULT_TYPE_INT, SC_NONE); + ParseDeclSpec (&Spec, TS_DEFAULT_TYPE_INT | TS_FUNCTION_SPEC, SC_NONE); /* Don't accept illegal storage classes */ if ((Spec.StorageClass & SC_STORAGEMASK) == SC_AUTO || @@ -560,6 +560,10 @@ void Compile (const char* FileName) if ((Entry->Flags & SC_STORAGEMASK) == SC_STATIC && SymIsRef (Entry)) { Warning ("Static function '%s' used but never defined", Entry->Name); + } else if ((Entry->Flags & SC_INLINE) != 0) { + Warning ("Inline function '%s' %s but never defined", + Entry->Name, + SymIsRef (Entry) ? "used" : "declared"); } } } diff --git a/src/cc65/declare.c b/src/cc65/declare.c index f93305f01..6173b5460 100644 --- a/src/cc65/declare.c +++ b/src/cc65/declare.c @@ -124,9 +124,37 @@ static unsigned ParseOneStorageClass (void) +static unsigned ParseOneFuncSpec (void) +/* Parse and return a function specifier */ +{ + unsigned FuncSpec = 0; + + /* Check the function specifier given */ + switch (CurTok.Tok) { + + case TOK_INLINE: + FuncSpec = SC_INLINE; + NextToken (); + break; + + case TOK_NORETURN: + FuncSpec = SC_NORETURN; + NextToken (); + break; + + default: + break; + } + + return FuncSpec; +} + + + static int ParseStorageClass (DeclSpec* Spec) /* Parse storage class specifiers. Return true if a specifier is read even if -** it was duplicated or disallowed. */ +** it was duplicated or disallowed. +*/ { /* Check the storage class given */ unsigned StorageClass = ParseOneStorageClass (); @@ -151,6 +179,31 @@ static int ParseStorageClass (DeclSpec* Spec) +static int ParseFuncSpecClass (DeclSpec* Spec) +/* Parse function specifiers. Return true if a specifier is read even if it +** was duplicated or disallowed. +*/ +{ + /* Check the function specifiers given */ + unsigned FuncSpec = ParseOneFuncSpec (); + + if (FuncSpec == 0) { + return 0; + } + + while (FuncSpec != 0) { + if ((Spec->StorageClass & FuncSpec) != 0) { + Warning ("Duplicate function specifier"); + } + Spec->StorageClass |= FuncSpec; + FuncSpec = ParseOneFuncSpec (); + } + + return 1; +} + + + static void DuplicateQualifier (const char* Name) /* Print an error message */ { @@ -303,7 +356,8 @@ static void OptionalSpecifiers (DeclSpec* Spec, TypeCode* Qualifiers, typespec_t */ { TypeCode Q = T_QUAL_NONE; - int Continue; + int HasStorageClass; + int HasFuncSpec; do { /* There may be type qualifiers *before* any storage class specifiers */ @@ -311,11 +365,17 @@ static void OptionalSpecifiers (DeclSpec* Spec, TypeCode* Qualifiers, typespec_t *Qualifiers |= Q; /* Parse storage class specifiers anyway then check */ - Continue = ParseStorageClass (Spec); - if (Continue && (TSFlags & (TS_STORAGE_CLASS_SPEC | TS_FUNCTION_SPEC)) == 0) { + HasStorageClass = ParseStorageClass (Spec); + if (HasStorageClass && (TSFlags & TS_STORAGE_CLASS_SPEC) == 0) { Error ("Unexpected storage class specified"); } - } while (Continue || Q != T_QUAL_NONE); + + /* Parse function specifiers anyway then check */ + HasFuncSpec = ParseFuncSpecClass (Spec); + if (HasFuncSpec && (TSFlags & TS_FUNCTION_SPEC) == 0) { + Error ("Unexpected function specifiers"); + } + } while (Q != T_QUAL_NONE || HasStorageClass || HasFuncSpec); } @@ -2375,6 +2435,14 @@ int ParseDecl (DeclSpec* Spec, Declarator* D, declmode_t Mode) /* Parse attributes for this declarator */ ParseAttribute (D); + /* 'inline' is only allowed on functions */ + if (Mode != DM_ACCEPT_PARAM_IDENT && + (D->StorageClass & SC_TYPEMASK) != SC_FUNC && + (D->StorageClass & SC_INLINE) == SC_INLINE) { + Error ("'inline' on non-function declaration"); + D->StorageClass &= ~SC_INLINE; + } + /* Check a few pre-C99 things */ if (D->Ident[0] != '\0' && (Spec->Flags & DS_TYPE_MASK) == DS_DEF_TYPE) { /* Check and warn about an implicit int return in the function */ @@ -2478,7 +2546,7 @@ void ParseDeclSpec (DeclSpec* Spec, typespec_t TSFlags, unsigned DefStorage) Spec->Flags &= ~DS_DEF_STORAGE; /* Parse the type specifiers */ - ParseTypeSpec (Spec, TSFlags | TS_STORAGE_CLASS_SPEC | TS_FUNCTION_SPEC); + ParseTypeSpec (Spec, TSFlags | TS_STORAGE_CLASS_SPEC); /* If no explicit storage class is given, use the default */ if ((Spec->StorageClass & SC_STORAGEMASK) == 0) { @@ -2495,7 +2563,9 @@ void CheckEmptyDecl (const DeclSpec* Spec) ** warning if not. */ { - if ((Spec->Flags & DS_TYPE_MASK) == DS_NONE) { + if ((Spec->StorageClass & SC_INLINE) == SC_INLINE) { + Error ("'inline' on empty declaration"); + } else if ((Spec->Flags & DS_TYPE_MASK) == DS_NONE) { /* No declaration at all */ } else if ((Spec->Flags & DS_EXTRA_TYPE) == 0) { Warning ("Declaration does not declare anything"); diff --git a/src/cc65/expr.c b/src/cc65/expr.c index e5e5cc62e..a855e5b3c 100644 --- a/src/cc65/expr.c +++ b/src/cc65/expr.c @@ -1407,7 +1407,7 @@ static void Primary (ExprDesc* E) } else { /* Let's see if this is a C99-style declaration */ DeclSpec Spec; - ParseDeclSpec (&Spec, TS_DEFAULT_TYPE_NONE, SC_AUTO); + ParseDeclSpec (&Spec, TS_DEFAULT_TYPE_NONE | TS_FUNCTION_SPEC, SC_AUTO); if ((Spec.Flags & DS_TYPE_MASK) != DS_NONE) { Error ("Mixed declarations and code are not supported in cc65"); diff --git a/src/cc65/function.c b/src/cc65/function.c index d570c2dde..596f9b617 100644 --- a/src/cc65/function.c +++ b/src/cc65/function.c @@ -518,6 +518,12 @@ void NewFunc (SymEntry* Func, FuncDesc* D) Error ("'main' cannot be declared as __fastcall__"); } + /* main() cannot be an inline function */ + if ((Func->Flags & SC_INLINE) == SC_INLINE) { + Error ("'main' cannot be declared inline"); + Func->Flags &= ~SC_INLINE; + } + /* Check return type */ if (GetUnqualRawTypeCode (ReturnType) == T_INT) { /* Determine if this is a main function in a C99 environment that diff --git a/src/cc65/locals.c b/src/cc65/locals.c index 28e263bb8..777f6b8b9 100644 --- a/src/cc65/locals.c +++ b/src/cc65/locals.c @@ -563,7 +563,7 @@ void DeclareLocals (void) } /* Read the declaration specifier */ - ParseDeclSpec (&Spec, TS_DEFAULT_TYPE_INT, SC_AUTO); + ParseDeclSpec (&Spec, TS_DEFAULT_TYPE_INT | TS_FUNCTION_SPEC, SC_AUTO); /* Check variable declarations. We need distinguish between a default ** int type and the end of variable declarations. So we will do the diff --git a/src/cc65/scanner.h b/src/cc65/scanner.h index ccf3a8805..6fc3e5370 100644 --- a/src/cc65/scanner.h +++ b/src/cc65/scanner.h @@ -76,6 +76,7 @@ typedef enum token_t { /* Function specifiers */ TOK_INLINE, + TOK_NORETURN, TOK_FASTCALL, TOK_CDECL, diff --git a/src/cc65/symentry.h b/src/cc65/symentry.h index 7bfc18ea4..7871b9ade 100644 --- a/src/cc65/symentry.h +++ b/src/cc65/symentry.h @@ -151,6 +151,10 @@ struct CodeEntry; #define SC_THREAD 0x08000000U /* UNSUPPORTED: Thread-local storage class */ #define SC_STORAGEMASK 0x0F000000U /* Storage type mask */ +/* Function specifiers */ +#define SC_INLINE 0x10000000U /* Inline function */ +#define SC_NORETURN 0x20000000U /* Noreturn function */ + /* Label definition or reference */ diff --git a/src/cc65/symtab.c b/src/cc65/symtab.c index a76e60450..f5ef2a15c 100644 --- a/src/cc65/symtab.c +++ b/src/cc65/symtab.c @@ -1439,6 +1439,16 @@ SymEntry* AddGlobalSym (const char* Name, const Type* T, unsigned Flags) Entry->V.F.WrappedCall = WrappedCall; Entry->V.F.WrappedCallData = WrappedCallData; } + + /* A files cope function declaration with the 'extern' storage + ** class or without the 'inline' specifier ensures that the + ** function definition (if any) is a non-inline definition. + */ + if (SymTab == SymTab0 && + ((Flags & SC_STORAGEMASK) == SC_EXTERN || + (Flags & SC_INLINE) == 0)) { + Entry->Flags |= SC_NOINLINEDEF; + } } /* Add an alias of the global symbol to the local symbol table */ @@ -1575,7 +1585,7 @@ void EmitExternals (void) if (SymIsRef (Entry) && !SymIsDef (Entry)) { /* An import */ g_defimport (Entry->Name, Flags & SC_ZEROPAGE); - } else if (SymIsDef (Entry)) { + } else if (SymIsDef (Entry) && ((Flags & SC_NOINLINEDEF) || (Flags & SC_INLINE) == 0)) { /* An export */ g_defexport (Entry->Name, Flags & SC_ZEROPAGE); } diff --git a/test/ref/Makefile b/test/ref/Makefile index 9ecb33c00..5c189c6cb 100644 --- a/test/ref/Makefile +++ b/test/ref/Makefile @@ -63,6 +63,7 @@ CUSTOMSOURCES = \ # exact error output is required ERRORSOURCES = \ custom-reference-error.c \ + inline-error.c \ bug1889-missing-identifier.c \ bug2312-preprocessor-error.c diff --git a/test/ref/bug1889-missing-identifier.cref b/test/ref/bug1889-missing-identifier.cref index 6317657d1..e77c1a7a1 100644 --- a/test/ref/bug1889-missing-identifier.cref +++ b/test/ref/bug1889-missing-identifier.cref @@ -1,4 +1,4 @@ bug1889-missing-identifier.c:3: Error: Identifier or ';' expected after declaration specifiers bug1889-missing-identifier.c:3: Warning: Implicit 'int' is an obsolete feature -bug1889-missing-identifier.c:4: Error: Declaration specifier or identifier expected +bug1889-missing-identifier.c:4: Error: 'inline' on empty declaration bug1889-missing-identifier.c:6: Error: Expression expected diff --git a/test/ref/inline-error.c b/test/ref/inline-error.c new file mode 100644 index 000000000..d8191025a --- /dev/null +++ b/test/ref/inline-error.c @@ -0,0 +1,36 @@ +/* C99 inline in declarations */ + +inline typedef int; /* Error */ +static inline int; /* Error */ +inline static int a1; /* Error */ +int inline (*fp1)(void); /* Error */ +typedef inline int f1_t(void); /* Error */ +inline int f1a(void); /* OK here warning later */ +inline extern int f1b(void); /* OK here warning later */ +extern inline int f1b(void); /* Same as above */ +inline static int f1c(void); /* OK here warning later */ +static inline int f1c(void); /* Same as above */ + +void foo(inline int x); /* Error */ +int a = sizeof (inline int); /* TODO: better error message */ +int b = sizeof (inline int (int)); /* TODO: better error message */ + +inline int main(void) /* Error */ +{ + inline typedef int; /* Error */ + static inline int; /* Error */ + extern inline int a2; /* Error */ + int inline (*fp2)(void); /* Error */ + typedef inline int f2_t(void); /* Error */ + inline int f2a(void); /* OK here warning later */ + inline extern int f2b(void); /* OK here warning later */ + extern inline int f2b(void); /* Same as above */ + + f1a(); /* Still imported */ + f1b(); /* Still imported */ + f1c(); /* Not imported */ + f2a(); /* Still imported */ + f2b(); /* Still imported */ +} + +/* Warning: non-external inline functions declared but undefined in TU */ diff --git a/test/ref/inline-error.cref b/test/ref/inline-error.cref new file mode 100644 index 000000000..abfdcdddd --- /dev/null +++ b/test/ref/inline-error.cref @@ -0,0 +1,20 @@ +inline-error.c:3: Error: 'inline' on empty declaration +inline-error.c:4: Error: 'inline' on empty declaration +inline-error.c:5: Error: 'inline' on non-function declaration +inline-error.c:6: Error: 'inline' on non-function declaration +inline-error.c:7: Error: 'inline' on non-function declaration +inline-error.c:14: Error: Unexpected function specifiers +inline-error.c:15: Error: Mixed declarations and code are not supported in cc65 +inline-error.c:16: Error: Mixed declarations and code are not supported in cc65 +inline-error.c:19: Error: 'main' cannot be declared inline +inline-error.c:20: Error: 'inline' on empty declaration +inline-error.c:21: Error: 'inline' on empty declaration +inline-error.c:22: Error: 'inline' on non-function declaration +inline-error.c:23: Error: 'inline' on non-function declaration +inline-error.c:24: Error: 'inline' on non-function declaration +inline-error.c:34: Warning: Variable 'fp2' is defined but never used +inline-error.c:37: Warning: Inline function 'f1a' used but never defined +inline-error.c:37: Warning: Inline function 'f1b' used but never defined +inline-error.c:37: Warning: Static function 'f1c' used but never defined +inline-error.c:37: Warning: Inline function 'f2a' used but never defined +inline-error.c:37: Warning: Inline function 'f2b' used but never defined diff --git a/test/val/inline-func.c b/test/val/inline-func.c new file mode 100644 index 000000000..b9e127aae --- /dev/null +++ b/test/val/inline-func.c @@ -0,0 +1,20 @@ +/* C99 inline */ + +#include + +inline static int f(int x, ...) +{ + return x * 2; +} + +extern inline int g(int x); + +int main(void) +{ + return f(g(7)) == 42 ? EXIT_SUCCESS : EXIT_FAILURE; +} + +int g(int x) +{ + return x * 3; +} From b388ca0236940bd45402a63af901f325309f5f8d Mon Sep 17 00:00:00 2001 From: Colin Leroy-Mira Date: Mon, 15 Jan 2024 21:51:17 +0100 Subject: [PATCH 03/16] Fix #2357 - Copy est.size and flags of op when moving it --- src/cc65/coptlong.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/cc65/coptlong.c b/src/cc65/coptlong.c index 16f089e49..b378021b5 100644 --- a/src/cc65/coptlong.c +++ b/src/cc65/coptlong.c @@ -106,9 +106,13 @@ unsigned OptLongAssign (CodeSeg* S) !RegXUsed (S, I+11)) { L[1]->AM = L[11]->AM; + L[1]->Size = L[11]->Size; + L[1]->Flags = L[11]->Flags; CE_SetArg(L[1], L[11]->Arg); L[3]->AM = L[9]->AM; + L[3]->Size = L[9]->Size; + L[3]->Flags = L[9]->Flags; CE_SetArg(L[3], L[9]->Arg); CS_DelEntries (S, I+8, 4); @@ -188,9 +192,13 @@ unsigned OptLongCopy (CodeSeg* S) !RegXUsed (S, I+11)) { L[1]->AM = L[11]->AM; + L[1]->Size = L[11]->Size; + L[1]->Flags = L[11]->Flags; CE_SetArg(L[1], L[11]->Arg); L[3]->AM = L[9]->AM; + L[3]->Size = L[9]->Size; + L[3]->Flags = L[9]->Flags; CE_SetArg(L[3], L[9]->Arg); CS_DelEntries (S, I+8, 4); From 2c4ebe812c9ba5ddf0ae08d3294d78e14507d0b2 Mon Sep 17 00:00:00 2001 From: Bob Andrews Date: Mon, 15 Jan 2024 23:03:13 +0100 Subject: [PATCH 04/16] Revert "Fix #2357 - Copy est.size and flags of op when moving it" --- src/cc65/coptlong.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/cc65/coptlong.c b/src/cc65/coptlong.c index 7e30ef42e..29cf4d353 100644 --- a/src/cc65/coptlong.c +++ b/src/cc65/coptlong.c @@ -120,13 +120,9 @@ unsigned OptLongAssign (CodeSeg* S) !CS_RangeHasLabel(S, I, 12)) { L[1]->AM = L[11]->AM; - L[1]->Size = L[11]->Size; - L[1]->Flags = L[11]->Flags; CE_SetArg(L[1], L[11]->Arg); L[3]->AM = L[9]->AM; - L[3]->Size = L[9]->Size; - L[3]->Flags = L[9]->Flags; CE_SetArg(L[3], L[9]->Arg); CS_DelEntries (S, I+8, 4); @@ -215,13 +211,9 @@ unsigned OptLongCopy (CodeSeg* S) !CS_RangeHasLabel(S, I, 12)) { L[1]->AM = L[11]->AM; - L[1]->Size = L[11]->Size; - L[1]->Flags = L[11]->Flags; CE_SetArg(L[1], L[11]->Arg); L[3]->AM = L[9]->AM; - L[3]->Size = L[9]->Size; - L[3]->Flags = L[9]->Flags; CE_SetArg(L[3], L[9]->Arg); CS_DelEntries (S, I+8, 4); From dec65176f03f77592018f0ddb44411c0a5ddf0a7 Mon Sep 17 00:00:00 2001 From: Colin Leroy-Mira Date: Mon, 15 Jan 2024 21:51:17 +0100 Subject: [PATCH 05/16] Fix #2357 - Copy est.size and flags of op when moving it --- src/cc65/coptlong.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/cc65/coptlong.c b/src/cc65/coptlong.c index 29cf4d353..7e30ef42e 100644 --- a/src/cc65/coptlong.c +++ b/src/cc65/coptlong.c @@ -120,9 +120,13 @@ unsigned OptLongAssign (CodeSeg* S) !CS_RangeHasLabel(S, I, 12)) { L[1]->AM = L[11]->AM; + L[1]->Size = L[11]->Size; + L[1]->Flags = L[11]->Flags; CE_SetArg(L[1], L[11]->Arg); L[3]->AM = L[9]->AM; + L[3]->Size = L[9]->Size; + L[3]->Flags = L[9]->Flags; CE_SetArg(L[3], L[9]->Arg); CS_DelEntries (S, I+8, 4); @@ -211,9 +215,13 @@ unsigned OptLongCopy (CodeSeg* S) !CS_RangeHasLabel(S, I, 12)) { L[1]->AM = L[11]->AM; + L[1]->Size = L[11]->Size; + L[1]->Flags = L[11]->Flags; CE_SetArg(L[1], L[11]->Arg); L[3]->AM = L[9]->AM; + L[3]->Size = L[9]->Size; + L[3]->Flags = L[9]->Flags; CE_SetArg(L[3], L[9]->Arg); CS_DelEntries (S, I+8, 4); From db8ac355cb7d4f32d820041bccf3a6905565bdad Mon Sep 17 00:00:00 2001 From: Colin Leroy-Mira Date: Tue, 16 Jan 2024 09:33:33 +0100 Subject: [PATCH 06/16] Cleaner updating of instructions --- src/cc65/coptlong.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/src/cc65/coptlong.c b/src/cc65/coptlong.c index 7e30ef42e..23c30875a 100644 --- a/src/cc65/coptlong.c +++ b/src/cc65/coptlong.c @@ -87,6 +87,7 @@ unsigned OptLongAssign (CodeSeg* S) L[0] = CS_GetEntry (S, I); if (CS_GetEntries (S, L+1, I+1, 12)) { + CodeEntry* N; if (/* Check the opcode sequence */ L[0]->OPC == OP65_LDA && L[1]->OPC == OP65_STA && @@ -119,15 +120,13 @@ unsigned OptLongAssign (CodeSeg* S) !RegXUsed (S, I+12) && !CS_RangeHasLabel(S, I, 12)) { - L[1]->AM = L[11]->AM; - L[1]->Size = L[11]->Size; - L[1]->Flags = L[11]->Flags; - CE_SetArg(L[1], L[11]->Arg); + N = NewCodeEntry (OP65_STA, L[11]->AM, L[11]->Arg, 0, L[11]->LI); + CS_DelEntry (S, I+1); + CS_InsertEntry (S, N, I+1); - L[3]->AM = L[9]->AM; - L[3]->Size = L[9]->Size; - L[3]->Flags = L[9]->Flags; - CE_SetArg(L[3], L[9]->Arg); + N = NewCodeEntry (OP65_STA, L[9]->AM, L[9]->Arg, 0, L[9]->LI); + CS_DelEntry (S, I+3); + CS_InsertEntry (S, N, I+3); CS_DelEntries (S, I+8, 4); @@ -183,6 +182,7 @@ unsigned OptLongCopy (CodeSeg* S) L[0] = CS_GetEntry (S, I); if (CS_GetEntries (S, L+1, I+1, 12)) { + CodeEntry *N; if (L[0]->OPC == OP65_LDA && !strncmp(L[0]->Arg, L[5]->Arg, strlen(L[5]->Arg)) && !strcmp(L[0]->Arg + strlen(L[5]->Arg), "+3") && @@ -214,15 +214,13 @@ unsigned OptLongCopy (CodeSeg* S) !RegXUsed (S, I+11) && !CS_RangeHasLabel(S, I, 12)) { - L[1]->AM = L[11]->AM; - L[1]->Size = L[11]->Size; - L[1]->Flags = L[11]->Flags; - CE_SetArg(L[1], L[11]->Arg); + N = NewCodeEntry (OP65_STA, L[11]->AM, L[11]->Arg, 0, L[11]->LI); + CS_DelEntry (S, I+1); + CS_InsertEntry (S, N, I+1); - L[3]->AM = L[9]->AM; - L[3]->Size = L[9]->Size; - L[3]->Flags = L[9]->Flags; - CE_SetArg(L[3], L[9]->Arg); + N = NewCodeEntry (OP65_STA, L[9]->AM, L[9]->Arg, 0, L[9]->LI); + CS_DelEntry (S, I+3); + CS_InsertEntry (S, N, I+3); CS_DelEntries (S, I+8, 4); From 0c53e7e0da864e65c62559b0037794bd024e0900 Mon Sep 17 00:00:00 2001 From: Colin Leroy-Mira Date: Tue, 16 Jan 2024 20:50:50 +0100 Subject: [PATCH 07/16] Add test case for bug #2357 --- test/val/bug2357.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 test/val/bug2357.c diff --git a/test/val/bug2357.c b/test/val/bug2357.c new file mode 100644 index 000000000..a0cff0d19 --- /dev/null +++ b/test/val/bug2357.c @@ -0,0 +1,38 @@ +/* bug #2357 - Compiler produces invalid code after d8a3938 +*/ + +unsigned long test; + +unsigned long longarray[7]; + +void jsr_threebytes(void) { + +} + +/* having replaced two sty $zp with two sta $abs, but forgetting + * to update the instruction size, coptlong.c could cause a build + * error "Error: Range error (131 not in [-128..127])" if the + * computed codesize was under 126, but the real codesize was above + * 127. + * This tests verifies that the bug is fixed. + */ +unsigned char __fastcall__ foo (unsigned char res) +{ + if (res == 0) { + longarray[1]=test; /* 24 bytes - but the compiler thought 22 */ + longarray[2]=test; /* 48 bytes - but 44 */ + longarray[3]=test; /* 72 bytes - 66 */ + longarray[4]=test; /* 96 bytes - 88 */ + longarray[6]=test; /* 120 bytes - 110 */ + jsr_threebytes(); /* 123 - 113 */ + jsr_threebytes(); /* 126 - 116 */ + jsr_threebytes(); /* 129 - 119 */ + } + return 0; +} + +int main (void) +{ + foo(42); + return 0; +} From 9471e128b5091838695ab9695b3145d33ac6b22f Mon Sep 17 00:00:00 2001 From: acqn Date: Thu, 18 Jan 2024 20:59:46 +0800 Subject: [PATCH 08/16] Fixed segname pragmas right after a function definition. --- src/cc65/function.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/cc65/function.c b/src/cc65/function.c index 4b4060f2a..d570c2dde 100644 --- a/src/cc65/function.c +++ b/src/cc65/function.c @@ -685,9 +685,6 @@ void NewFunc (SymEntry* Func, FuncDesc* D) /* Leave the lexical level */ LeaveFunctionLevel (); - /* Eat the closing brace */ - ConsumeRCurly (); - /* Restore the old literal pool, remembering the one for the function */ Func->V.F.LitPool = PopLiteralPool (); @@ -699,6 +696,12 @@ void NewFunc (SymEntry* Func, FuncDesc* D) /* Switch back to the old segments */ PopSegContext (); + /* Eat the closing brace after we've done everything with the function + ** definition. This way we won't have troubles with pragmas right after + ** the closing brace. + */ + ConsumeRCurly(); + /* Reset the current function pointer */ FreeFunction (CurrentFunc); CurrentFunc = 0; From 166a4b25f7fa6eb9b0ccb3a785a6fabf36492af1 Mon Sep 17 00:00:00 2001 From: Colin Leroy-Mira Date: Sun, 14 Jan 2024 18:27:41 +0100 Subject: [PATCH 09/16] Apple2: implement sleep using MONWAIT Also publish detect_iigs(), set_iigs_speed() and get_iigs_speed(). Refactor to only store one ostype variable. --- doc/apple2.sgml | 16 ++++++++ doc/apple2enh.sgml | 16 ++++++++ doc/funcref.sgml | 70 ++++++++++++++++++++++++++++++++++ include/accelerator.h | 32 +++++++++++++++- libsrc/apple2/detect_iigs.s | 17 +++++++++ libsrc/apple2/get_iigs_speed.s | 22 +++++++++++ libsrc/apple2/get_ostype.s | 2 +- libsrc/apple2/set_iigs_speed.s | 29 ++++++++++++++ libsrc/apple2/sleep.s | 54 ++++++++++++++++++++++++++ libsrc/apple2/wait.s | 20 ++++++++++ libsrc/apple2/waitvsync.s | 16 +------- 11 files changed, 277 insertions(+), 17 deletions(-) create mode 100644 libsrc/apple2/detect_iigs.s create mode 100644 libsrc/apple2/get_iigs_speed.s create mode 100644 libsrc/apple2/set_iigs_speed.s create mode 100644 libsrc/apple2/sleep.s create mode 100644 libsrc/apple2/wait.s diff --git a/doc/apple2.sgml b/doc/apple2.sgml index f1603c428..fb49ea941 100644 --- a/doc/apple2.sgml +++ b/doc/apple2.sgml @@ -331,12 +331,28 @@ usage. _filetype _datetime get_ostype +gmtime_dt +mktime_dt rebootafterexit ser_apple2_slot tgi_apple2_mix +Apple IIgs specific functions in accelerator.h

+ +In addition to those, the for declaration and +usage. + + +detect_iigs +get_iigs_speed +set_iigs_speed + + + Hardware access

There's currently no support for direct hardware access. This does not mean diff --git a/doc/apple2enh.sgml b/doc/apple2enh.sgml index e27501577..593b226ba 100644 --- a/doc/apple2enh.sgml +++ b/doc/apple2enh.sgml @@ -332,6 +332,8 @@ usage. _filetype _datetime get_ostype +gmtime_dt +mktime_dt rebootafterexit ser_apple2_slot tgi_apple2_mix @@ -340,6 +342,20 @@ usage. +Apple IIgs specific functions in accelerator.h

+ +In addition to those, the for declaration and +usage. + + +detect_iigs +get_iigs_speed +set_iigs_speed + + + Hardware access

There's currently no support for direct hardware access. This does not mean diff --git a/doc/funcref.sgml b/doc/funcref.sgml index c8a818295..740a6d62e 100644 --- a/doc/funcref.sgml +++ b/doc/funcref.sgml @@ -71,18 +71,21 @@ function. + + + @@ -104,6 +107,8 @@ function. _dos_type + + rebootafterexit @@ -3453,6 +3458,26 @@ used in presence of a prototype. +detect_iigs

+ + + +/ + +The function is specific to the Apple2 and Apple2enh platforms. + +, +, + + + + detect_scpu

@@ -4167,6 +4192,27 @@ header files define constants that can be used to check the return code. +get_iigs_speed

+ + + +/ + +The function is specific to the Apple2 and Apple2enh platforms. +See the accelerator.h header for the speed definitions. + +, +, + + + + get_scpu_speed

@@ -6985,6 +7031,30 @@ clean-up when exiting the program. +set_iigs_speed

+ + + +/ + +The function is specific to the Apple2 and Apple2enh platforms. +See the accelerator.h header for the speed definitions. +Accepted parameters are SPEED_SLOW and SPEED_FAST (all other values are +considered SPEED_FAST). + +, +, + + + + set_scpu_speed

diff --git a/include/accelerator.h b/include/accelerator.h index b5d8d0194..0137a7fed 100644 --- a/include/accelerator.h +++ b/include/accelerator.h @@ -304,6 +304,36 @@ unsigned char detect_turbomaster (void); * 0x01 : C64 Turbo Master cartridge present */ +unsigned char __fastcall__ set_iigs_speed (unsigned char speed); + +/* Set the speed of the Apple IIgs CPU. + * + * Possible values: + * SPEED_SLOW : 1 Mhz mode + * SPEED_FAST : Fast mode (2.8MHz or more, depending on the presence of + * an accelerator) + * + * Any other value will be interpreted as SPEED_FAST. + */ + +unsigned char get_iigs_speed (void); + +/* Get the speed of the Apple IIgs CPU. + * + * Possible return values: + * SPEED_SLOW : 1 Mhz mode + * SPEED_FAST : Fast mode (2.8MHz or more, depending on the presence of + * an accelerator) + */ + +unsigned char detect_iigs (void); + +/* Check whether we are running on an Apple IIgs. + * + * Possible return values: + * 0x00 : No + * 0x01 : Yes + */ + /* End of accelerator.h */ #endif - diff --git a/libsrc/apple2/detect_iigs.s b/libsrc/apple2/detect_iigs.s new file mode 100644 index 000000000..f82a464ac --- /dev/null +++ b/libsrc/apple2/detect_iigs.s @@ -0,0 +1,17 @@ +; +; Colin Leroy-Mira , 2024 +; +; void __fastcall__ detect_iigs(void) +; + + .export _detect_iigs + .import ostype, return0, return1 + + .include "apple2.inc" + + ; Returns 1 if running on IIgs, 0 otherwise +_detect_iigs: + lda ostype + bpl :+ + jmp return1 +: jmp return0 diff --git a/libsrc/apple2/get_iigs_speed.s b/libsrc/apple2/get_iigs_speed.s new file mode 100644 index 000000000..1915d7773 --- /dev/null +++ b/libsrc/apple2/get_iigs_speed.s @@ -0,0 +1,22 @@ +; +; Colin Leroy-Mira , 2024 +; +; unsigned char __fastcall__ get_iigs_speed(void) +; + + .export _get_iigs_speed + .import ostype, return0 + + .include "apple2.inc" + .include "accelerator.inc" + +_get_iigs_speed: + lda ostype ; Return SLOW if not IIgs + bpl :+ + lda CYAREG ; Check current setting + bpl :+ + lda #SPEED_FAST + ldx #$00 + rts + .assert SPEED_SLOW = 0, error +: jmp return0 ; SPEED_SLOW diff --git a/libsrc/apple2/get_ostype.s b/libsrc/apple2/get_ostype.s index a1b1eb5be..ea9ff25cc 100644 --- a/libsrc/apple2/get_ostype.s +++ b/libsrc/apple2/get_ostype.s @@ -5,7 +5,7 @@ ; .constructor initostype, 9 - .export _get_ostype + .export _get_ostype, ostype ; Identify machine according to: ; Apple II Miscellaneous TechNote #7, Apple II Family Identification diff --git a/libsrc/apple2/set_iigs_speed.s b/libsrc/apple2/set_iigs_speed.s new file mode 100644 index 000000000..5e2f2f722 --- /dev/null +++ b/libsrc/apple2/set_iigs_speed.s @@ -0,0 +1,29 @@ +; +; Colin Leroy-Mira , 2024 +; +; unsigned char __fastcall__ detect_iigs(unsigned char speed) +; + + .export _set_iigs_speed + .import ostype, return0 + + .include "apple2.inc" + .include "accelerator.inc" + +_set_iigs_speed: + tax ; Keep parameter + lda ostype ; Return if not IIgs + bmi :+ + jmp return0 + +: lda CYAREG + cpx #SPEED_SLOW + beq :+ + ora #%10000000 + bne set_speed +: and #%01111111 +set_speed: + sta CYAREG + txa + ldx #$00 + rts diff --git a/libsrc/apple2/sleep.s b/libsrc/apple2/sleep.s new file mode 100644 index 000000000..43873d9f4 --- /dev/null +++ b/libsrc/apple2/sleep.s @@ -0,0 +1,54 @@ +; +; Colin Leroy-Mira , 2024 +; +; void __fastcall__ sleep(unsigned s) +; +; + + .export _sleep + .import _get_iigs_speed + .import _set_iigs_speed + .import WAIT + .importzp tmp1 + + .include "accelerator.inc" + + ; This functions uses the Apple2 WAIT ROM routine to waste a certain + ; amount of cycles and returns approximately after the numbers of + ; seconds passed in AX. + ; + ; It takes 1023730 cycles when called with AX=1 (1,0007s), + ; 10236364 cycles when called with AX=10 (10,006 seconds), + ; 306064298 cycles with AX=300 (299.2 seconds). + ; + ; Caveat: IRQs firing during calls to sleep will make the sleep longer + ; by the amount of cycles it takes to handle the IRQ. + ; +_sleep: + stx tmp1 ; High byte of s in X + tay ; Low byte in A + ora tmp1 + bne :+ + rts +: jsr _get_iigs_speed ; Save current CPU speed + pha + lda #SPEED_SLOW ; Down to 1MHz for consistency around WAIT + jsr _set_iigs_speed +sleep_1s: + ldx #$0A ; Loop 10 times +sleep_100ms: + lda #$C7 ; Sleep about 99ms + jsr WAIT + lda #$0D ; About 1ms + jsr WAIT + dex + bne sleep_100ms + dey + bne sleep_1s + dec tmp1 + bmi done + dey ; Down to #$FF + bne sleep_1s +done: + pla ; Restore CPU speed + jmp _set_iigs_speed diff --git a/libsrc/apple2/wait.s b/libsrc/apple2/wait.s new file mode 100644 index 000000000..3b569215b --- /dev/null +++ b/libsrc/apple2/wait.s @@ -0,0 +1,20 @@ +; +; Colin Leroy-Mira, 2024 +; +; WAIT routine +; + + .export WAIT + + .include "apple2.inc" + + .segment "LOWCODE" + +WAIT: + ; Switch in ROM and call WAIT + bit $C082 + jsr $FCA8 ; Vector to WAIT routine + + ; Switch in LC bank 2 for R/O and return + bit $C080 + rts diff --git a/libsrc/apple2/waitvsync.s b/libsrc/apple2/waitvsync.s index a4ab5ebb3..1697622de 100644 --- a/libsrc/apple2/waitvsync.s +++ b/libsrc/apple2/waitvsync.s @@ -5,21 +5,11 @@ ; .ifdef __APPLE2ENH__ - .constructor initvsync .export _waitvsync - .import _get_ostype + .import ostype .include "apple2.inc" - .segment "ONCE" - -initvsync: - jsr _get_ostype - sta ostype - rts - - .code - _waitvsync: bit ostype bmi iigs ; $8x @@ -53,8 +43,4 @@ iic: sei cli rts - .segment "INIT" - -ostype: .res 1 - .endif ; __APPLE2ENH__ From d906748691d31dc8ec1dfd95d1314bec11a149a1 Mon Sep 17 00:00:00 2001 From: Alex Thissen Date: Thu, 18 Jan 2024 17:37:09 +0100 Subject: [PATCH 10/16] Fix uploader implementation to reset IRQ bit for timer 4 (serial) interrupt --- libsrc/lynx/uploader.s | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libsrc/lynx/uploader.s b/libsrc/lynx/uploader.s index f16a1721a..df3e5df40 100644 --- a/libsrc/lynx/uploader.s +++ b/libsrc/lynx/uploader.s @@ -33,7 +33,7 @@ loop1: cont1: jsr read_byte sta (load_ptr2),y - sta PALETTE ; feedback ;-) + sta PALETTE + 1 ; feedback ;-) iny bne loop1 inc load_ptr2+1 @@ -69,6 +69,8 @@ again: ; last action : clear interrupt ; exit: + lda #$10 + sta INTRST clc rts From 93f9cb6e489e248a2f92c0b103d330b9e78ee220 Mon Sep 17 00:00:00 2001 From: Alex Thissen Date: Thu, 18 Jan 2024 18:06:10 +0100 Subject: [PATCH 11/16] Adjusted uploader configuration. Split into two MEMORY areas, so it can be just below video memory. --- cfg/lynx-uploader.cfg | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/cfg/lynx-uploader.cfg b/cfg/lynx-uploader.cfg index 476b3c5de..ea217626c 100644 --- a/cfg/lynx-uploader.cfg +++ b/cfg/lynx-uploader.cfg @@ -5,16 +5,17 @@ SYMBOLS { __BANK1BLOCKSIZE__: type = weak, value = $0000; # bank 1 block size __EXEHDR__: type = import; __BOOTLDR__: type = import; - __DEFDIR__: type = import; __UPLOADER__: type = import; + __UPLOADERSIZE__: type = export, value = $61; + __HEADERSIZE__: type = export, value = 64; } MEMORY { ZP: file = "", define = yes, start = $0000, size = $0100; - HEADER: file = %O, start = $0000, size = $0040; + HEADER: file = %O, start = $0000, size = __HEADERSIZE__; BOOT: file = %O, start = $0200, size = __STARTOFDIRECTORY__; - DIR: file = %O, start = $0000, size = 8; - MAIN: file = %O, define = yes, start = $0200, size = $BD38 - __STACKSIZE__; - UPLDR: file = %O, define = yes, start = $BFDC, size = $005C; + DIR: file = %O, start = $0000, size = 16; + MAIN: file = %O, define = yes, start = $0200, size = $C038 - __UPLOADERSIZE__ - $200 - __STACKSIZE__; + UPLOAD: file = %O, define = yes, start = $C038 - __UPLOADERSIZE__, size = $0061; } SEGMENTS { ZEROPAGE: load = ZP, type = zp; @@ -30,8 +31,8 @@ SEGMENTS { RODATA: load = MAIN, type = ro, define = yes; DATA: load = MAIN, type = rw, define = yes; BSS: load = MAIN, type = bss, define = yes; - UPCODE: load = UPLDR, type = ro, define = yes; - UPDATA: load = UPLDR, type = rw, define = yes; + UPCODE: load = UPLOAD, type = ro, define = yes; + UPDATA: load = UPLOAD, type = rw, define = yes; } FEATURES { CONDES: type = constructor, From acce24fedcfa4d37dc5a28bf18129b68cb2194f9 Mon Sep 17 00:00:00 2001 From: Alex Thissen Date: Thu, 18 Jan 2024 18:13:02 +0100 Subject: [PATCH 12/16] Switched to __BANK0BLOCKSIZE__ instead of __BLOCKSIZE__ to make current lynx config files work --- libsrc/lynx/lynx-cart.s | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsrc/lynx/lynx-cart.s b/libsrc/lynx/lynx-cart.s index 94edff677..f9417aed3 100644 --- a/libsrc/lynx/lynx-cart.s +++ b/libsrc/lynx/lynx-cart.s @@ -88,7 +88,7 @@ lynxblock: lda __iodat sta IODAT stz _FileBlockByte - lda #<($100-(>__BLOCKSIZE__)) + lda #<($100-(>__BANK0BLOCKSIZE__)) sta _FileBlockByte+1 ply plx From 2e56dcc52196a8fdd65416adcc46c7e834db4615 Mon Sep 17 00:00:00 2001 From: Alex Thissen Date: Thu, 18 Jan 2024 18:13:39 +0100 Subject: [PATCH 13/16] Fix for mising import --- libsrc/lynx/lynx-cart.s | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsrc/lynx/lynx-cart.s b/libsrc/lynx/lynx-cart.s index f9417aed3..d1f3e33eb 100644 --- a/libsrc/lynx/lynx-cart.s +++ b/libsrc/lynx/lynx-cart.s @@ -17,7 +17,7 @@ .include "extzp.inc" .export lynxskip0, lynxread0 .export lynxblock - .import __BLOCKSIZE__ + .import __BANK0BLOCKSIZE__ .code From ad90a3a421776d9c13756de5e5cdb53fa7b5a469 Mon Sep 17 00:00:00 2001 From: Alex Thissen Date: Thu, 18 Jan 2024 18:57:57 +0000 Subject: [PATCH 14/16] Replaced references to __BLOCKSIZE__ with __BANK0BLOCKSIZE__ --- libsrc/lynx/lseek.s | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libsrc/lynx/lseek.s b/libsrc/lynx/lseek.s index 4b4f94d7c..04d816945 100644 --- a/libsrc/lynx/lseek.s +++ b/libsrc/lynx/lseek.s @@ -18,7 +18,7 @@ .import ldeaxysp, decsp2, pushax, incsp8 .import tosandeax,decax1,tosdiveax,axlong,ldaxysp .import lynxskip0, lynxblock,tosasreax - .import __BLOCKSIZE__ + .import __BANK0BLOCKSIZE__ .importzp _FileCurrBlock .segment "CODE" @@ -32,15 +32,15 @@ jsr ldeaxysp jsr pusheax ldx #$00 - lda #<(__BLOCKSIZE__/1024 + 9) + lda #<(__BANK0BLOCKSIZE__/1024 + 9) jsr tosasreax sta _FileCurrBlock jsr lynxblock ldy #$05 jsr ldeaxysp jsr pusheax - lda #<(__BLOCKSIZE__-1) - ldx #>(__BLOCKSIZE__-1) + lda #<(__BANK0BLOCKSIZE__-1) + ldx #>(__BANK0BLOCKSIZE__-1) jsr axlong jsr tosandeax eor #$FF From 83691f30c1442aacb769d9eb3841802d2817beb8 Mon Sep 17 00:00:00 2001 From: Alex Thissen Date: Fri, 19 Jan 2024 10:52:42 +0000 Subject: [PATCH 15/16] Missed a tab in config --- cfg/lynx-uploader.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cfg/lynx-uploader.cfg b/cfg/lynx-uploader.cfg index ea217626c..62269de90 100644 --- a/cfg/lynx-uploader.cfg +++ b/cfg/lynx-uploader.cfg @@ -15,7 +15,7 @@ MEMORY { BOOT: file = %O, start = $0200, size = __STARTOFDIRECTORY__; DIR: file = %O, start = $0000, size = 16; MAIN: file = %O, define = yes, start = $0200, size = $C038 - __UPLOADERSIZE__ - $200 - __STACKSIZE__; - UPLOAD: file = %O, define = yes, start = $C038 - __UPLOADERSIZE__, size = $0061; + UPLOAD: file = %O, define = yes, start = $C038 - __UPLOADERSIZE__, size = $0061; } SEGMENTS { ZEROPAGE: load = ZP, type = zp; From b23a7ec40746d68c90582dc4ec78ea822dd5d1b6 Mon Sep 17 00:00:00 2001 From: Colin Leroy-Mira Date: Fri, 19 Jan 2024 21:14:47 +0100 Subject: [PATCH 16/16] Save two bytes in pushax and popptr1 It's not because Y must equal zero on rts that we should'nt spare one byte and one cycle. --- libsrc/runtime/popptr1.s | 8 +++++++- libsrc/runtime/pushax.s | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/libsrc/runtime/popptr1.s b/libsrc/runtime/popptr1.s index 1d04330ab..b54bb9eb3 100644 --- a/libsrc/runtime/popptr1.s +++ b/libsrc/runtime/popptr1.s @@ -8,12 +8,18 @@ .import incsp2 .importzp sp, ptr1 + .macpack cpu + .proc popptr1 ; 14 bytes (four usages = at least 2 bytes saved) ldy #1 lda (sp),y ; get hi byte sta ptr1+1 ; into ptr hi - dey ; no optimization for 65C02 here to have Y=0 at exit! + dey ; dey even for for 65C02 here to have Y=0 at exit! +.if (.cpu .bitand ::CPU_ISET_65SC02) + lda (sp) ; get lo byte +.else lda (sp),y ; get lo byte +.endif sta ptr1 ; to ptr lo jmp incsp2 .endproc diff --git a/libsrc/runtime/pushax.s b/libsrc/runtime/pushax.s index ac181b994..27ddf641d 100644 --- a/libsrc/runtime/pushax.s +++ b/libsrc/runtime/pushax.s @@ -7,6 +7,8 @@ .export push0, pusha0, pushax .importzp sp + .macpack cpu + push0: lda #0 pusha0: ldx #0 @@ -29,7 +31,11 @@ pusha0: ldx #0 sta (sp),y ; (27) pla ; (31) dey ; (33) +.if (.cpu .bitand ::CPU_ISET_65SC02) + sta (sp) ; (37) +.else sta (sp),y ; (38) - rts ; (44) +.endif + rts ; (44/43) .endproc