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:
3
.github/workflows/build-on-pull-request.yml
vendored
3
.github/workflows/build-on-pull-request.yml
vendored
@@ -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
|
||||
|
||||
1
Makefile
1
Makefile
@@ -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
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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
|
||||
|
||||
15
src/Makefile
15
src/Makefile
@@ -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)
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
|
||||
@@ -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
40
test/val/bug2608.c
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user