1
0
mirror of https://github.com/cc65/cc65.git synced 2026-03-10 17:21:49 +00:00

Merge branch 'master' into checksorted

This commit is contained in:
Bob Andrews
2025-06-12 23:33:12 +02:00
committed by GitHub
12 changed files with 312 additions and 43 deletions

View File

@@ -30,6 +30,9 @@ jobs:
- name: Build the tools.
shell: bash
run: make -j2 bin USER_CFLAGS=-Werror
- name: Build the dbginfo example
shell: bash
run: make -j2 -C src test
- name: Build the utilities.
shell: bash
run: make -j2 util

View File

@@ -55,6 +55,7 @@ test:
check:
@$(MAKE) -C .github/checks checkstyle --no-print-directory
@$(MAKE) -C .github/checks sorted --no-print-directory
@$(MAKE) -C src test --no-print-directory
@$(MAKE) test
@$(MAKE) -C targettest platforms --no-print-directory
@$(MAKE) -C samples platforms --no-print-directory

View File

@@ -1154,6 +1154,96 @@ The compiler defines several macros at startup:
<item><tt/__CC65_STD_CC65__/
</itemize>
<label id="macro-CPU">
<tag><tt>__CPU__</tt></tag>
This macro contains a bitset that allows to check if a specific instruction
set is supported. For example, the 65C02 CPU supports all instructions of the
65SC02. So testing for the instruction set of the 65SC02 using the following
check will succeed for both CPUs (and also for the 65816 and HUC6280).
<tscreen><verb>
#if (__CPU__ & __CPU_ISET_65SC02__)
</verb></tscreen>
This is much simpler and more future proof than checking for specific CPUs.
The compiler defines a set of constants named <tt/__CPU_ISET_xxx/ to do the
checks. The <tt/__CPU__/ variable is usually derived from the target system
given, but can be changed using the <tt/<ref id="option--cpu" name="--cpu">/
command line option.
<tag><tt>__CPU_6502__</tt></tag>
This macro is defined if the code is compiled for a 6502 CPU.
<tag><tt>__CPU_6502X__</tt></tag>
This macro is defined if the code is compiled for a 6502 CPU with invalid
opcodes.
<tag><tt>__CPU_6502DTV__</tt></tag>
This macro is defined if the code is compiled for a DTV CPU.
<tag><tt>__CPU_65SC02__</tt></tag>
This macro is defined if the code is compiled for a 65SC02 CPU.
<tag><tt>__CPU_65C02__</tt></tag>
This macro is defined if the code is compiled for a 65C02 CPU.
<tag><tt>__CPU_65816__</tt></tag>
This macro is defined if the code is compiled for a 65816 CPU.
<tag><tt>__CPU_HUC6280__</tt></tag>
This macro is defined if the code is compiled for a HUC6280 CPU.
<tag><tt>__CPU_ISET_6502__</tt></tag>
This macro expands to a numeric constant that can be used to check the
<tt/<ref id="macro-CPU" name="__CPU__">/ macro for the instruction set
of the 6502 CPU.
<tag><tt>__CPU_ISET_6502X__</tt></tag>
This macro expands to a numeric constant that can be used to check the
<tt/<ref id="macro-CPU" name="__CPU__">/ macro for the instruction set
of the 6502X CPU.
<tag><tt>__CPU_ISET_6502DTV__</tt></tag>
This macro expands to a numeric constant that can be used to check the
<tt/<ref id="macro-CPU" name="__CPU__">/ macro for the instruction set
of the 6502DTV CPU.
<tag><tt>__CPU_ISET_65SC02__</tt></tag>
This macro expands to a numeric constant that can be used to check the
<tt/<ref id="macro-CPU" name="__CPU__">/ macro for the instruction set
of the 65SC02 CPU.
<tag><tt>__CPU_ISET_65C02__</tt></tag>
This macro expands to a numeric constant that can be used to check the
<tt/<ref id="macro-CPU" name="__CPU__">/ macro for the instruction set
of the 65C02 CPU.
<tag><tt>__CPU_ISET_65816__</tt></tag>
This macro expands to a numeric constant that can be used to check the
<tt/<ref id="macro-CPU" name="__CPU__">/ macro for the instruction set
of the 65816 CPU.
<tag><tt>__CPU_ISET_HUC6280__</tt></tag>
This macro expands to a numeric constant that can be used to check the
<tt/<ref id="macro-CPU" name="__CPU__">/ macro for the instruction set
of the HUC6280 CPU.
<tag><tt>__CX16__</tt></tag>
This macro is defined if the target is the Commander X16 (-t cx16).

View File

@@ -40,6 +40,20 @@
/*****************************************************************************/
#if (__CPU__ & __CPU_ISET_65SC02__)
/* Always inline, three bytes is not more than a jsr */
#define ntohs(x) \
( \
__AX__=(x), \
asm("phx"), \
asm("tax"), \
asm("pla"), \
__AX__ \
)
#define htons(x) ntohs(x)
#else
#if (__OPT_i__ < 200)
int __fastcall__ ntohs (int val);
@@ -56,12 +70,12 @@ int __fastcall__ htons (int val);
)
#define htons(x) ntohs(x)
#endif
#endif /* __OPT_i__ < 200 */
#endif /* __CPU__ & __CPU_ISET_65SC02__ */
long __fastcall__ ntohl (long val);
long __fastcall__ htonl (long val);
/* End of arpa/inet.h */
#endif

View File

@@ -168,4 +168,19 @@ $(eval $(call OBJS_template,common))
$(foreach prog,$(PROGS),$(eval $(call PROG_template,$(prog))))
.PHONY: dbginfo dbgsh test
test: dbginfo dbgsh
$(eval $(call OBJS_template,dbginfo))
dbginfo: $(dbginfo_OBJS)
../wrk/dbgsh$(EXE_SUFFIX): $(dbginfo_OBJS) ../wrk/common/common.a
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS)
dbgsh: ../wrk/dbgsh$(EXE_SUFFIX)
-include $(DEPS)

View File

@@ -317,6 +317,81 @@ static void SetSys (const char* Sys)
static void DefineCpuMacros (void)
/* Define macros for the target CPU */
{
const char* CPUName;
/* Note: The list of CPUs handled here must match the one checked in
** OptCPU().
*/
switch (CPU) {
/* The following ones are legal CPUs as far as the assembler is
** concerned but are ruled out earlier in the compiler, so this
** function should never see them.
*/
case CPU_NONE:
case CPU_SWEET16:
case CPU_M740:
case CPU_4510:
case CPU_UNKNOWN:
CPUName = (CPU == CPU_UNKNOWN)? "unknown" : CPUNames[CPU];
Internal ("Invalid CPU \"%s\"", CPUName);
break;
case CPU_6502:
DefineNumericMacro ("__CPU_6502__", 1);
break;
case CPU_6502X:
DefineNumericMacro ("__CPU_6502X__", 1);
break;
case CPU_6502DTV:
DefineNumericMacro ("__CPU_6502DTV__", 1);
break;
case CPU_65SC02:
DefineNumericMacro ("__CPU_65SC02__", 1);
break;
case CPU_65C02:
DefineNumericMacro ("__CPU_65C02__", 1);
break;
case CPU_65816:
DefineNumericMacro ("__CPU_65816__", 1);
break;
case CPU_HUC6280:
DefineNumericMacro ("__CPU_HUC6280__", 1);
break;
default:
FAIL ("Unexpected value in switch");
break;
}
/* Define the macros for instruction sets. We only include the ones for
** the available CPUs.
*/
DefineNumericMacro ("__CPU_ISET_6502__", CPU_ISET_6502);
DefineNumericMacro ("__CPU_ISET_6502X__", CPU_ISET_6502X);
DefineNumericMacro ("__CPU_ISET_6502DTV__", CPU_ISET_6502DTV);
DefineNumericMacro ("__CPU_ISET_65SC02__", CPU_ISET_65SC02);
DefineNumericMacro ("__CPU_ISET_65C02__", CPU_ISET_65C02);
DefineNumericMacro ("__CPU_ISET_65816__", CPU_ISET_65816);
DefineNumericMacro ("__CPU_ISET_HUC6280__", CPU_ISET_HUC6280);
/* Now define the macro that contains the bit set with the available
** cpu instructions.
*/
DefineNumericMacro ("__CPU__", CPUIsets[CPU]);
}
static void FileNameOption (const char* Opt, const char* Arg, StrBuf* Name)
/* Handle an option that remembers a file name for later */
{
@@ -477,7 +552,9 @@ static void OptCreateFullDep (const char* Opt attribute ((unused)),
static void OptCPU (const char* Opt, const char* Arg)
/* Handle the --cpu option */
{
/* Find the CPU from the given name */
/* Find the CPU from the given name. We do only accept a certain number
** of CPUs. If the list is changed, be sure to adjust SetCpuMacros().
*/
CPU = FindCPU (Arg);
if (CPU != CPU_6502 && CPU != CPU_6502X && CPU != CPU_65SC02 &&
CPU != CPU_65C02 && CPU != CPU_65816 && CPU != CPU_HUC6280 &&
@@ -1063,7 +1140,9 @@ int main (int argc, char* argv[])
/* Create the output file name if it was not explicitly given */
MakeDefaultOutputName (InputFile);
/* If no CPU given, use the default CPU for the target */
/* If no CPU given, use the default CPU for the target. Define macros that
** allow to query the CPU.
*/
if (CPU == CPU_UNKNOWN) {
if (Target != TGT_UNKNOWN) {
CPU = GetTargetProperties (Target)->DefaultCPU;
@@ -1071,6 +1150,7 @@ int main (int argc, char* argv[])
CPU = CPU_6502;
}
}
DefineCpuMacros ();
/* If no memory model was given, use the default */
if (MemoryModel == MMODEL_UNKNOWN) {

View File

@@ -436,12 +436,7 @@ static void ApplySegNamePragma (pragma_t Token, int PushPop, const char* Name, u
SetSegAddrSize (Name, AddrSize);
}
/* BSS variables are output at the end of the compilation. Don't
** bother to change their segment, now.
*/
if (Seg != SEG_BSS) {
g_segname (Seg);
}
g_segname (Seg);
}

View File

@@ -122,6 +122,11 @@ static int DoAssemble = 1;
/* The name of the output file, NULL if none given */
static const char* OutputName = 0;
/* The path part of the output file, NULL if none given
** or the OutputName is just a filename with no path
** information. */
static char *OutputDirectory = 0;
/* The name of the linker configuration file if given */
static const char* LinkerConfig = 0;
@@ -555,7 +560,7 @@ static void AssembleFile (const char* File, const char* TmpFile, unsigned ArgCou
if (TmpFile) {
ObjName = MakeFilename (TmpFile, ".o");
} else {
ObjName = MakeTmpFilename (".o");
ObjName = MakeTmpFilename (OutputDirectory, File, ".o");
}
CmdSetOutput (&CA65, ObjName);
CmdAddFile (&LD65, ObjName);
@@ -684,7 +689,7 @@ static void Compile (const char* File)
if (DoAssemble) {
/* set a temporary output file name */
TmpFile = MakeTmpFilename(".s");
TmpFile = MakeTmpFilename(OutputDirectory, File, ".s");
CmdSetOutput (&CC65, TmpFile);
}
@@ -729,7 +734,7 @@ static void CompileRes (const char* File)
** BEFORE adding the file
*/
if (DoAssemble && DoLink) {
AsmName = MakeTmpFilename(".s");
AsmName = MakeTmpFilename(OutputDirectory, File, ".s");
CmdSetAsmOutput(&GRC, AsmName);
}
@@ -1623,6 +1628,7 @@ int main (int argc, char* argv [])
case 'o':
/* Name the output file */
OutputName = GetArg (&I, 2);
OutputDirectory = GetFileDirectory(OutputName);
break;
case 'r':
@@ -1713,6 +1719,9 @@ int main (int argc, char* argv [])
}
RemoveTempFiles ();
if (OutputDirectory != NULL) {
xfree(OutputDirectory);
}
/* Return an apropriate exit code */
return EXIT_SUCCESS;

View File

@@ -33,8 +33,17 @@
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#if defined(_MSC_VER)
# include <process.h>
#else
# include <unistd.h>
#endif
#include "xmalloc.h"
#include "fname.h"
@@ -93,7 +102,28 @@ const char* FindName (const char* Path)
return Path + Len;
}
char *GetFileDirectory (const char* File)
/* Return a copy of the path part of a File, or NULL if there is none. */
{
char *Out, *P;
if (File == NULL) {
return NULL;
}
Out = xmalloc (strlen (File) + 1);
strcpy(Out, File);
P = (char *)FindName (Out);
if (P == Out) {
/* This is a simple filename. */
xfree (Out);
return NULL;
}
*P = '\0';
return Out;
}
char* MakeFilename (const char* Origin, const char* Ext)
/* Make a new file name from Origin and Ext. If Origin has an extension, it
@@ -119,35 +149,22 @@ char* MakeFilename (const char* Origin, const char* Ext)
char* MakeTmpFilename (const char* Ext)
/* Make a new temporary file name from Ext. tmpnam(3) is called
** and Ext is appended to generate the filename.
char* MakeTmpFilename (const char *Directory, const char *Origin, const char* Ext)
/* Make a new temporary file name from Origin and Ext.
** The result is placed in a malloc'ed buffer and returned.
*/
{
char* Out;
char Buffer[L_tmpnam * 2]; /* a lazy way to ensure we have space for Ext */
size_t Len = 0;
/*
** gcc emits the following warning here:
**
** warning: the use of `tmpnam' is dangerous, better use `mkstemp'
**
** however, mkstemp actually opens a file, which we do not want.
** tmpfile() is unsuitable for the same reason.
**
** we could write our own version, but then we would have to struggle
** with supporting multiple build environments.
**
** tmpnam(3) is safe here, because ca65 / cc65 / ld65 will simply clobber
** an existing file, or exit if with an error if they are unable to.
**
** gcc will also complain, if you don't use the return value from tmpnam(3)
*/
strcat(tmpnam(Buffer), Ext);
Out = xmalloc (strlen (Buffer) + 1);
strcpy (Out, Buffer);
/* Allocate template */
if (Directory != NULL) {
Len = strlen (Directory);
}
Len += strlen (Origin) + strlen (".2147483648") + strlen (Ext) + 1;
Out = xmalloc (Len);
snprintf (Out, Len, "%s%s.%u%s", (Directory != NULL ? Directory : ""),
FindName(Origin), getpid(), Ext);
return Out;
}

View File

@@ -52,6 +52,9 @@ const char* FindName (const char* Path);
** the file, the function returns Path as name.
*/
char *GetFileDirectory (const char* File);
/* Return a copy of the path part of a File, or NULL if there is none. */
char* MakeFilename (const char* Origin, const char* Ext);
/* Make a new file name from Origin and Ext. If Origin has an extension, it
** is removed and Ext is appended. If Origin has no extension, Ext is simply
@@ -59,9 +62,10 @@ char* MakeFilename (const char* Origin, const char* Ext);
** The function may be used to create "foo.o" from "foo.s".
*/
char* MakeTmpFilename (const char* Ext);
/* Make a new temporary file name from Ext. tmpnam(3) is called
** and Ext is appended to generate the filename.
char* MakeTmpFilename (const char *Directory, const char *Origin, const char* Ext);
/* Make a new temporary file name from Directory, Origin, and Ext.
** A temporary path is generated from the Directory,
** the Origin filename, the compiler's PID and the Extension.
** The result is placed in a malloc'ed buffer and returned.
*/

View File

@@ -47,10 +47,11 @@ _Pragma _Pragma (
#pragma bss-name("BSS")
{
extern int y;
#pragma bss-name("BSS2")
#pragma bss-name("BSS") // used to be BSS2, but fix for #2608 means
// that now causes ld65 to fail, so we use BSS instead
static
#pragma zpsym ("y")
int x; // TODO: currently in "BSS", but supposed to be in "BSS2"?
int x;
x = 0;
if (memcmp(str, "aBC", 3))

40
test/val/bug2608.c Normal file
View File

@@ -0,0 +1,40 @@
/* bug #2608: "zp_bss" is placed in BSS and NOT placed in ZEROPAGE as expected. */
#include <stdlib.h>
#include <stdio.h>
int err = 0;
int is_zeropage(void *p)
{
if (/*(p >= ((void*)0)) &&*/
(p <= ((void*)0xff))) {
return 1;
}
return 0;
}
void foo(void) {
#pragma bss-name(push,"ZEROPAGE")
#pragma data-name(push,"ZEROPAGE")
static int zp_data = 5;
static char zp_bss;
#pragma bss-name(pop)
#pragma data-name(pop)
printf("zp_data at 0x%04x (%szp)\n", &zp_data, is_zeropage(&zp_data) ? "" : "NOT ");
printf("zp_bss at 0x%04x (%szp)\n", &zp_bss, is_zeropage(&zp_bss) ? "" : "NOT ");
if (!is_zeropage(&zp_data)) {
err++;
}
if (!is_zeropage(&zp_bss)) {
err++;
}
}
int main(void)
{
foo();
printf("errors: %d\n", err);
return err;
}