Unnamed labels
-If you really want to write messy code, there are also unnamed labels. These
-labels do not have a name (you guessed that already, didn't you?). A colon is
-used to mark the absence of the name.
+If you really want to write messy code, there are also unnamed labels. To define
+an unnamed label, use either @: (.LOCALCHAR is respected if it
+is set) or sole : .
-Unnamed labels may be accessed by using the colon plus several minus or plus
-characters as a label designator. Using the '-' characters will create a back
-reference (use the n'th label backwards), using '+' will create a forward
-reference (use the n'th label in forward direction). An example will help to
-understand this:
+To reference an unnamed label, use @ (.LOCALCHAR is respected
+if it is set) or : with several - or + characters.
+The - characters will create a back reference (n'th label backwards),
+the + will create a forward reference (n'th label in forward direction).
+As an alternative, angle brackets < and > may be used
+instead of - and + with the same meaning.
+
+Example:
- : lda (ptr1),y ; #1
- cmp (ptr2),y
- bne :+ ; -> #2
- tax
- beq :+++ ; -> #4
- iny
- bne :- ; -> #1
- inc ptr1+1
- inc ptr2+1
- bne :- ; -> #1
-
- : bcs :+ ; #2 -> #3
- ldx #$FF
- rts
-
- : ldx #$01 ; #3
- : rts ; #4
+ cpy #0
+ beq @++
+ @:
+ sta $2007
+ dey
+ bne @-
+ @:
+ rts
-As you can see from the example, unnamed labels will make even short
-sections of code hard to understand, because you have to count labels
-to find branch targets (this is the reason why I for my part do
-prefer the "cheap" local labels). Nevertheless, unnamed labels are
-convenient in some situations, so it's your decision.
+Unnamed labels may make even short sections of code hard to understand, because
+you have to count labels to find branch targets. It's better to prefer the
+"cheap" local labels. Nevertheless, unnamed labels are convenient in some
+situations, so it's up to your discretion.
organize named symbols, not
unnamed ones, so scopes don't have an effect on unnamed labels.
-
Using macros to define labels and constants
While there are drawbacks with this approach, it may be handy in a few rare
diff --git a/doc/cc65.sgml b/doc/cc65.sgml
index efe48b61b..d08e8418d 100644
--- a/doc/cc65.sgml
+++ b/doc/cc65.sgml
@@ -61,7 +61,7 @@ Short options:
-Os Inline some standard functions
-T Include source as comment
-V Print the compiler version number
- -W warning[,...] Suppress warnings
+ -W [-+]warning[,...] Control warnings ('-' disables, '+' enables)
-d Debug mode
-g Add debug info to object file
-h Help (this text)
@@ -84,8 +84,9 @@ Long options:
--create-full-dep name Create a full make dependency file
--data-name seg Set the name of the DATA segment
--debug Debug mode
+ --debug-tables name Write symbol table debug info to a file
--debug-info Add debug info to object file
- --debug-opt name Configure optimizations with a file
+ --debug-opt name Debug optimization steps
--debug-opt-output Debug output of each optimization step
--dep-target target Use this dependency target
--disable-opt name Disable an optimization step
@@ -823,6 +824,11 @@ and the one defined by the ISO standard:
as it sounds, since the 6502 has so few registers that it isn't
possible to keep values in registers anyway.
+- In
+ command line option.
+
There may be some more minor differences I'm currently not aware of. The
@@ -1273,6 +1279,12 @@ If the first parameter is #pragma allow-eager-inline ([push,] on|off)
diff --git a/doc/cx16.sgml b/doc/cx16.sgml
index 78a51206b..a718e52fa 100644
--- a/doc/cx16.sgml
+++ b/doc/cx16.sgml
@@ -243,6 +243,12 @@ point to
+
+
+ This driver features a resolution of 640 across and 480 down with 2 colors,
+ black and white.
+
+
Extended memory drivers
diff --git a/doc/funcref.sgml b/doc/funcref.sgml
index 81c63a38b..ea2350aad 100644
--- a/doc/funcref.sgml
+++ b/doc/funcref.sgml
@@ -95,6 +95,7 @@ function.
- _dos_type
+
- allow_lowercase
[
][
][
@@ -154,6 +155,7 @@ function.
][
][
][
+][
]
@@ -780,6 +782,7 @@ communication, see also testcode/lib/ser-test.c .
[
][
][
+][
][
][
][
@@ -7899,22 +7902,47 @@ be used in presence of a prototype.
-]strstr
+strcasestr
-/
-
- The function is only available as fastcall function, so it may only
be used in presence of a prototype.
,
+[,
+][
+]
+
+
+
+strstr
+
+
+
+/
+
+- The function is only available as fastcall function, so it may only
+be used in presence of a prototype.
+
+
,
[,
][
]
,
[,
][,
][,
@@ -8338,6 +8367,7 @@ only in the presence of a prototype.
]
diff --git a/doc/sim65.sgml b/doc/sim65.sgml
index c2740bbad..962f07254 100644
--- a/doc/sim65.sgml
+++ b/doc/sim65.sgml
@@ -115,37 +115,78 @@ PVExit ($01)
Creating a Test in C
-For a C test compiled and linked with ).
+a set of built-in paravirtualization functions (see [).
+Example:
+
+]
+#include
+int main()
+{
+ printf("Hello!\n");
+ return 5;
+}
+
+// Build and run:
+// cl65 -t sim6502 -o example.prg example.c
+// sim65 example.prg
+
+// Build and run, separate steps:
+// cc65 -t sim6502 -o example.s example.c
+// ca65 -t sim6502 -o example.o example.s
+// ld65 -t sim6502 -o example.prg example.o sim6502.lib
+// sim65 example.prg
+
Creating a Test in Assembly
-Assembly tests may similarly be assembled and linked with
-
- Return from
-The binary file has a 12 byte header:
+Example:
+
+
+.export _main
+_main:
+ lda #5
+ rts
+
+; Build and run:
+; cl65 -t sim6502 -o example.prg example.s
+; sim65 example.prg
+
+; Build and run, separate steps:
+; ca65 -t sim6502 -o example.o example.s
+; ld65 -t sim6502 -o example.prg example.o sim6502.lib
+; sim65 example.prg
+
+
+Internally, the binary program file has a 12 byte header provided by the library:
@@ -182,6 +223,9 @@ These use cc65 calling conventions, and are intended for use with the sim65 targ
The
diff --git a/include/apple2.h b/include/apple2.h
index 875c10661..1a840be6e 100644
--- a/include/apple2.h
+++ b/include/apple2.h
@@ -232,6 +232,16 @@ struct tm* __fastcall__ gmtime_dt (const struct datetime* dt);
time_t __fastcall__ mktime_dt (const struct datetime* dt);
/* Converts a ProDOS date/time structure to a time_t UNIX timestamp */
+#if !defined(__APPLE2ENH__)
+unsigned char __fastcall__ allow_lowercase (unsigned char onoff);
+/* If onoff is 0, lowercase characters printed to the screen via STDIO and
+** CONIO are forced to uppercase. If onoff is 1, lowercase characters are
+** printed to the screen untouched. By default lowercase characters are
+** forced to uppercase because a stock Apple ][+ doesn't support lowercase
+** display. The function returns the old lowercase setting.
+*/
+#endif
+
/* End of apple2.h */
diff --git a/include/atari.h b/include/atari.h
index 04cacab33..0af109264 100644
--- a/include/atari.h
+++ b/include/atari.h
@@ -220,17 +220,17 @@
/* Color register functions */
/*****************************************************************************/
-extern void __fastcall__ _setcolor (unsigned char color_reg, unsigned char hue, unsigned char luminance);
-extern void __fastcall__ _setcolor_low (unsigned char color_reg, unsigned char color_value);
-extern unsigned char __fastcall__ _getcolor (unsigned char color_reg);
+void __fastcall__ _setcolor (unsigned char color_reg, unsigned char hue, unsigned char luminance);
+void __fastcall__ _setcolor_low (unsigned char color_reg, unsigned char color_value);
+unsigned char __fastcall__ _getcolor (unsigned char color_reg);
/*****************************************************************************/
/* Other screen functions */
/*****************************************************************************/
-extern void waitvsync (void); /* wait for start of next frame */
-extern int __fastcall__ _graphics (unsigned char mode); /* mode value same as in BASIC */
-extern void __fastcall__ _scroll (signed char numlines);
+void waitvsync (void); /* wait for start of next frame */
+int __fastcall__ _graphics (unsigned char mode); /* mode value same as in BASIC */
+void __fastcall__ _scroll (signed char numlines);
/* numlines > 0 scrolls up */
/* numlines < 0 scrolls down */
@@ -239,18 +239,18 @@ extern void __fastcall__ _scroll (signed char numlines);
/* Sound function */
/*****************************************************************************/
-extern void __fastcall__ _sound (unsigned char voice, unsigned char frequency, unsigned char distortion, unsigned char volume);
+void __fastcall__ _sound (unsigned char voice, unsigned char frequency, unsigned char distortion, unsigned char volume);
/*****************************************************************************/
/* Misc. functions */
/*****************************************************************************/
-extern unsigned char get_ostype(void); /* get ROM version */
-extern unsigned char get_tv(void); /* get TV system */
-extern void _save_vecs(void); /* save system vectors */
-extern void _rest_vecs(void); /* restore system vectors */
-extern char *_getdefdev(void); /* get default floppy device */
-extern unsigned char _is_cmdline_dos(void); /* does DOS support command lines */
+unsigned char get_ostype(void); /* get ROM version */
+unsigned char get_tv(void); /* get TV system */
+void _save_vecs(void); /* save system vectors */
+void _rest_vecs(void); /* restore system vectors */
+char *_getdefdev(void); /* get default floppy device */
+unsigned char _is_cmdline_dos(void); /* does DOS support command lines */
/*****************************************************************************/
diff --git a/include/atari5200.h b/include/atari5200.h
index ff176c15b..9a0399d0e 100644
--- a/include/atari5200.h
+++ b/include/atari5200.h
@@ -94,7 +94,7 @@ extern void atr5200std_joy[]; /* referred to by joy_static_stddrv[] */
#define _bordercolor(color) 0
/* wait for start of next frame */
-extern void waitvsync (void);
+void waitvsync (void);
/* end of atari5200.h */
#endif
diff --git a/include/atari7800.h b/include/atari7800.h
index 3cbeedb8b..b289bb41e 100644
--- a/include/atari7800.h
+++ b/include/atari7800.h
@@ -52,7 +52,7 @@
/* No support for dynamically loadable drivers */
#define DYN_DRV 0
-extern unsigned char get_tv(void); /* get TV system */
+unsigned char get_tv(void); /* get TV system */
#include <_tia.h>
#define TIA (*(struct __tia*)0x0000)
diff --git a/include/atmos.h b/include/atmos.h
index 38d423c46..460a0010f 100644
--- a/include/atmos.h
+++ b/include/atmos.h
@@ -169,6 +169,9 @@ void atmos_tock (void);
void atmos_zap (void);
/* Raygun sound effect */
+void waitvsync (void);
+/* Wait for start of next frame */
+
/* End of atmos.h */
diff --git a/include/stdint.h b/include/stdint.h
index 5d6f04769..6d51565e0 100644
--- a/include/stdint.h
+++ b/include/stdint.h
@@ -52,15 +52,15 @@ typedef unsigned char uint8_t;
typedef unsigned uint16_t;
typedef unsigned long uint32_t;
-#define INT8_MIN ((int8_t) 0x80)
-#define INT8_MAX ((int8_t) 0x7F)
-#define INT16_MIN ((int16_t) 0x8000)
-#define INT16_MAX ((int16_t) 0x7FFF)
-#define INT32_MIN ((int32_t) 0x80000000)
-#define INT32_MAX ((int32_t) 0x7FFFFFFF)
-#define UINT8_MAX ((uint8_t) 0xFF)
-#define UINT16_MAX ((uint16_t) 0xFFFF)
-#define UINT32_MAX ((uint32_t) 0xFFFFFFFF)
+#define INT8_MIN -128
+#define INT8_MAX 127
+#define INT16_MIN (-32767 - 1)
+#define INT16_MAX 32767
+#define INT32_MIN (-2147483647L - 1L)
+#define INT32_MAX 2147483647L
+#define UINT8_MAX 255
+#define UINT16_MAX 65535U
+#define UINT32_MAX 4294967295UL
/* Minimum-width integer types */
typedef signed char int_least8_t;
@@ -70,15 +70,15 @@ typedef unsigned char uint_least8_t;
typedef unsigned uint_least16_t;
typedef unsigned long uint_least32_t;
-#define INT_LEAST8_MIN ((int_least8_t) 0x80)
-#define INT_LEAST8_MAX ((int_least8_t) 0x7F)
-#define INT_LEAST16_MIN ((int_least16_t) 0x8000)
-#define INT_LEAST16_MAX ((int_least16_t) 0x7FFF)
-#define INT_LEAST32_MIN ((int_least32_t) 0x80000000)
-#define INT_LEAST32_MAX ((int_least32_t) 0x7FFFFFFF)
-#define UINT_LEAST8_MAX ((uint_least8_t) 0xFF)
-#define UINT_LEAST16_MAX ((uint_least16_t) 0xFFFF)
-#define UINT_LEAST32_MAX ((uint_least32_t) 0xFFFFFFFF)
+#define INT_LEAST8_MIN INT8_MIN
+#define INT_LEAST8_MAX INT8_MAX
+#define INT_LEAST16_MIN INT16_MIN
+#define INT_LEAST16_MAX INT16_MAX
+#define INT_LEAST32_MIN INT32_MIN
+#define INT_LEAST32_MAX INT32_MAX
+#define UINT_LEAST8_MAX UINT8_MAX
+#define UINT_LEAST16_MAX UINT16_MAX
+#define UINT_LEAST32_MAX UINT32_MAX
/* Fastest minimum-width integer types */
typedef signed char int_fast8_t;
@@ -88,40 +88,40 @@ typedef unsigned char uint_fast8_t;
typedef unsigned uint_fast16_t;
typedef unsigned long uint_fast32_t;
-#define INT_FAST8_MIN ((int_fast8_t) 0x80)
-#define INT_FAST8_MAX ((int_fast8_t) 0x7F)
-#define INT_FAST16_MIN ((int_fast16_t) 0x8000)
-#define INT_FAST16_MAX ((int_fast16_t) 0x7FFF)
-#define INT_FAST32_MIN ((int_fast32_t) 0x80000000)
-#define INT_FAST32_MAX ((int_fast32_t) 0x7FFFFFFF)
-#define UINT_FAST8_MAX ((uint_fast8_t) 0xFF)
-#define UINT_FAST16_MAX ((uint_fast16_t) 0xFFFF)
-#define UINT_FAST32_MAX ((uint_fast32_t) 0xFFFFFFFF)
+#define INT_FAST8_MIN INT8_MIN
+#define INT_FAST8_MAX INT8_MAX
+#define INT_FAST16_MIN INT16_MIN
+#define INT_FAST16_MAX INT16_MAX
+#define INT_FAST32_MIN INT32_MIN
+#define INT_FAST32_MAX INT32_MAX
+#define UINT_FAST8_MAX UINT8_MAX
+#define UINT_FAST16_MAX UINT16_MAX
+#define UINT_FAST32_MAX UINT32_MAX
/* Integer types capable of holding object pointers */
typedef int intptr_t;
typedef unsigned uintptr_t;
-#define INTPTR_MIN ((intptr_t)0x8000)
-#define INTPTR_MAX ((intptr_t)0x7FFF)
-#define UINTPTR_MAX ((uintptr_t) 0xFFFF)
+#define INTPTR_MIN INT16_MIN
+#define INTPTR_MAX INT16_MAX
+#define UINTPTR_MAX UINT16_MAX
/* Greatest width integer types */
typedef long intmax_t;
typedef unsigned long uintmax_t;
-#define INTMAX_MIN ((intmax_t) 0x80000000)
-#define INTMAX_MAX ((intmax_t) 0x7FFFFFFF)
-#define UINTMAX_MAX ((uintmax_t) 0xFFFFFFFF)
+#define INTMAX_MIN INT32_MIN
+#define INTMAX_MAX INT32_MAX
+#define UINTMAX_MAX UINT32_MAX
/* Limits of other integer types */
-#define PTRDIFF_MIN ((int) 0x8000)
-#define PTRDIFF_MAX ((int) 0x7FFF)
+#define PTRDIFF_MIN INT16_MIN
+#define PTRDIFF_MAX INT16_MAX
-#define SIG_ATOMIC_MIN ((unsigned char) 0x00)
-#define SIG_ATOMIC_MAX ((unsigned char) 0xFF)
+#define SIG_ATOMIC_MIN 0
+#define SIG_ATOMIC_MAX UINT8_MAX
-#define SIZE_MAX 0xFFFF
+#define SIZE_MAX UINT16_MAX
/* Macros for minimum width integer constants */
#define INT8_C(c) c
diff --git a/include/string.h b/include/string.h
index abaf80e7d..3b7ece1d9 100644
--- a/include/string.h
+++ b/include/string.h
@@ -81,6 +81,7 @@ void __fastcall__ bzero (void* ptr, size_t n); /* BSD */
char* __fastcall__ strdup (const char* s); /* SYSV/BSD */
int __fastcall__ stricmp (const char* s1, const char* s2); /* DOS/Windows */
int __fastcall__ strcasecmp (const char* s1, const char* s2); /* Same for Unix */
+char* __fastcall__ strcasestr (const char* str, const char* substr);
int __fastcall__ strnicmp (const char* s1, const char* s2, size_t count); /* DOS/Windows */
int __fastcall__ strncasecmp (const char* s1, const char* s2, size_t count); /* Same for Unix */
size_t __fastcall__ strnlen (const char* s, size_t maxlen); /* POSIX.1-2008 */
@@ -89,6 +90,7 @@ char* __fastcall__ strlower (char* s);
char* __fastcall__ strupr (char* s);
char* __fastcall__ strupper (char* s);
char* __fastcall__ strqtok (char* s1, const char* s2);
+char* __fastcall__ stpcpy (char* dest, const char* src);
#endif
const char* __fastcall__ __stroserror (unsigned char errcode);
diff --git a/libsrc/NameClashes.md b/libsrc/NameClashes.md
new file mode 100644
index 000000000..ef2105602
--- /dev/null
+++ b/libsrc/NameClashes.md
@@ -0,0 +1,380 @@
+List of cc65 library name clashes
+=================================
+
+The following is a list of identifiers that might need
+to be fixed, sorted by directory and identifier:
+
+# common
+
+## \_\_argc
+
+* libsrc/runtime/callmain.s
+* libsrc/cbm610/mainargs.s
+* libsrc/cx16/mainargs.s
+* libsrc/plus4/mainargs.s
+* libsrc/lynx/mainargs.s
+* libsrc/c16/mainargs.s
+* libsrc/geos-common/system/mainargs.s
+* libsrc/sim6502/mainargs.s
+* libsrc/c128/mainargs.s
+* libsrc/vic20/mainargs.s
+* libsrc/nes/mainargs.s
+* libsrc/atari/getargs.s
+* libsrc/apple2/mainargs.s
+* libsrc/cbm510/mainargs.s
+* libsrc/telestrat/mainargs.s
+* libsrc/c64/mainargs.s
+* libsrc/pet/mainargs.s
+* libsrc/atmos/mainargs.s
+
+## \_\_argv
+
+* libsrc/runtime/callmain.s
+* libsrc/cbm610/mainargs.s
+* libsrc/cx16/mainargs.s
+* libsrc/plus4/mainargs.s
+* libsrc/lynx/mainargs.s
+* libsrc/c16/mainargs.s
+* libsrc/geos-common/system/mainargs.s
+* libsrc/sim6502/mainargs.s
+* libsrc/c128/mainargs.s
+* libsrc/vic20/mainargs.s
+* libsrc/nes/mainargs.s
+* libsrc/atari/getargs.s
+* libsrc/apple2/mainargs.s
+* libsrc/cbm510/mainargs.s
+* libsrc/telestrat/mainargs.s
+* libsrc/c64/mainargs.s
+* libsrc/pet/mainargs.s
+* libsrc/atmos/mainargs.s
+
+## \_\_cos
+
+* libsrc/common/sincos.s
+
+## \_\_ctypeidx
+
+* libsrc/common/ctype.s
+* libsrc/common/ctypemask.s
+* libsrc/geos-common/system/ctype.s
+* libsrc/atari/ctype.s
+* libsrc/cbm/ctype.s
+* libsrc/atmos/ctype.s
+* asminc/ctype\_common.inc
+
+## \_\_cwd
+
+* libsrc/common/getcwd.s
+* libsrc/common/_cwd.s
+* libsrc/atari/initcwd.s
+* libsrc/apple2/initcwd.s
+* libsrc/apple2/initcwd.s
+* libsrc/telestrat/initcwd.s
+* libsrc/cbm/initcwd.s
+
+## \_\_cwd\_buf\_size
+
+* libsrc/common/_cwd.s
+
+## \_\_envcount
+
+* libsrc/common/searchenv.s
+* libsrc/common/_environ.s
+* libsrc/common/putenv.s
+* libsrc/common/getenv.s
+
+## \_\_environ
+
+* libsrc/common/searchenv.s
+* libsrc/common/_environ.s
+* libsrc/common/putenv.s
+* libsrc/common/getenv.s
+
+## \_\_envsize
+
+* libsrc/common/_environ.s
+* libsrc/common/putenv.s
+
+## \_\_fdesc
+
+* libsrc/common/_fdesc.s
+* libsrc/common/fopen.s
+
+## \_\_filetab
+
+* libsrc/common/_fdesc.s
+* libsrc/common/_file.s
+* asminc/_file.inc
+
+## \_\_fopen
+
+* libsrc/common/fopen.s
+* libsrc/common/_fopen.s
+
+## \_\_printf
+
+* libsrc/common/vsnprintf.s
+* libsrc/common/_printf.s
+* libsrc/common/vfprintf.s
+* libsrc/conio/vcprintf.s
+* libsrc/pce/_printf.s
+
+## \_\_scanf
+
+* libsrc/common/_scanf.inc
+* libsrc/common/vsscanf.s
+* libsrc/conio/vcscanf.s
+
+## \_\_sin
+
+* libsrc/common/sincos.s
+
+## \_\_sys
+
+* libsrc/common/_sys.s
+* libsrc/apple2/_sys.s
+
+## \_\_sys\_oserrlist
+
+* libsrc/common/stroserr.s
+* libsrc/geos-common/system/oserrlist.s
+* libsrc/atari/oserrlist.s
+* libsrc/apple2/oserrlist.s
+* libsrc/cbm/oserrlist.s
+* libsrc/atmos/oserrlist.s
+
+## \_\_syschdir
+
+* libsrc/common/chdir.s
+* libsrc/atari/syschdir.s
+* libsrc/apple2/syschdir.s
+* libsrc/telestrat/syschdir.s
+* libsrc/cbm/syschdir.s
+
+## \_\_sysmkdir
+
+* libsrc/common/mkdir.s
+* libsrc/atari/sysmkdir.s
+* libsrc/apple2/sysmkdir.s
+* libsrc/telestrat/sysmkdir.s
+
+## \_\_sysremove
+
+* libsrc/common/remove.s
+* libsrc/geos-common/file/sysremove.s
+* libsrc/atari/sysremove.s
+* libsrc/atari/sysrmdir.s
+* libsrc/apple2/sysremove.s
+* libsrc/apple2/sysrmdir.s
+* libsrc/telestrat/sysremove.s
+* libsrc/cbm/sysremove.s
+
+## \_\_sysrename
+
+* libsrc/common/rename.s
+* libsrc/geos-common/file/sysrename.s
+* libsrc/atari/sysrename.s
+* libsrc/apple2/sysrename.s
+* libsrc/cbm/sysrename.s
+
+## \_\_sysrmdir
+
+* libsrc/common/rmdir.s
+* libsrc/atari/sysrmdir.s
+* libsrc/apple2/sysrmdir.s
+
+\_\_sysuname
+
+* libsrc/common/uname.s
+* libsrc/cbm610/sysuname.s
+* libsrc/cx16/sysuname.s
+* libsrc/plus4/sysuname.s
+* libsrc/lynx/sysuname.s
+* libsrc/c16/sysuname.s
+* libsrc/geos-common/system/sysuname.s
+* libsrc/c128/sysuname.s
+* libsrc/creativision/sysuname.s
+* libsrc/vic20/sysuname.s
+* libsrc/nes/sysuname.s
+* libsrc/atari/sysuname.s
+* libsrc/apple2/sysuname.s
+* libsrc/cbm510/sysuname.s
+* libsrc/telestrat/sysuname.s
+* libsrc/c64/sysuname.s
+* libsrc/pet/sysuname.s
+* libsrc/atari5200/sysuname.s
+* libsrc/atmos/sysuname.s
+
+# apple2
+
+## \_\_auxtype
+
+* libsrc/apple2/open.s
+
+## \_\_datetime
+
+* libsrc/apple2/open.s
+
+## \_\_dos\_type
+
+* libsrc/apple2/dioopen.s
+* libsrc/apple2/curdevice.s
+* libsrc/apple2/mainargs.s
+* libsrc/apple2/settime.s
+* libsrc/apple2/getdevice.s
+* libsrc/apple2/dosdetect.s
+* libsrc/apple2/irq.s
+* libsrc/apple2/open.s
+* libsrc/apple2/mli.s
+* libsrc/apple2/getres.s
+
+## \_\_filetype
+
+* libsrc/apple2/open.s
+* libsrc/apple2/exehdr.s
+
+## atari
+
+## \_\_defdev
+
+* libsrc/atari/posixdirent.s
+* libsrc/atari/ucase\_fn.s
+* libsrc/atari/getdefdev.s
+
+## \_\_dos\_type
+
+* libsrc/atari/getargs.s
+* libsrc/atari/exec.s
+* libsrc/atari/settime.s
+* libsrc/atari/syschdir.s
+* libsrc/atari/dosdetect.s
+* libsrc/atari/is\_cmdline\_dos.s
+* libsrc/atari/sysrmdir.s
+* libsrc/atari/gettime.s
+* libsrc/atari/lseek.s
+* libsrc/atari/getres.s
+* libsrc/atari/getdefdev.s
+
+## \_\_do\_oserror
+
+* libsrc/atari/posixdirent.s
+* libsrc/atari/do\_oserr.s
+* libsrc/atari/serref.s
+* libsrc/atari/read.s
+* libsrc/atari/write.s
+* libsrc/atari/close.s
+
+## \_\_getcolor
+
+* libsrc/atari/setcolor.s
+
+## \_\_getdefdev
+
+* libsrc/atari/getdefdev.s
+
+## \_\_graphics
+
+* libsrc/atari/graphics.s
+
+## \_\_inviocb
+
+* libsrc/atari/serref.s
+* libsrc/atari/ser/atrrdev.s
+* libsrc/atari/inviocb.s
+* libsrc/atari/read.s
+* libsrc/atari/write.s
+* libsrc/atari/lseek.s
+* libsrc/atari/close.s
+
+## \_\_is\_cmdline\_dos
+
+* libsrc/atari/is\_cmdline\_dos.s
+* libsrc/atari/doesclrscr.s
+
+## \_\_rest\_vecs
+
+* libsrc/atari/savevec.s
+
+## \_\_rwsetup
+
+* libsrc/atari/rwcommon.s
+* libsrc/atari/read.s
+* libsrc/atari/write.s
+
+## \_\_save\_vecs
+
+* libsrc/atari/savevec.s
+
+## \_\_scroll
+
+* libsrc/atari/scroll.s
+
+## \_\_setcolor
+
+* libsrc/atari/setcolor.s
+
+## \_\_setcolor\_low
+
+* libsrc/atari/setcolor.s
+
+## \_\_sio\_call
+
+* libsrc/atari/diowritev.s
+* libsrc/atari/diopncls.s
+* libsrc/atari/siocall.s
+* libsrc/atari/diowrite.s
+* libsrc/atari/dioread.s
+
+# cbm
+
+## \_\_cbm\_filetype
+
+* libsrc/cbm/cbm\_filetype.s
+* asminc/cbm\_filetype.in
+
+## \_\_dirread
+
+* libsrc/cbm/dir.inc
+* libsrc/cbm/dir.s
+
+## \_\_dirread1
+
+* libsrc/cbm/dir.inc
+* libsrc/cbm/dir.s
+
+# lynx
+
+## \_\_iodat
+
+* libsrc/lynx/lynx-cart.s
+* libsrc/lynx/bootldr.s
+* libsrc/lynx/extzp.s
+* libsrc/lynx/crt0.s
+* libsrc/lynx/extzp.inc
+
+## \_\_iodir
+
+* libsrc/lynx/extzp.s
+* libsrc/lynx/crt0.s
+* libsrc/lynx/extzp.inc
+
+## \_\_sprsys
+
+* libsrc/lynx/tgi/lynx-160-102-16.s
+* libsrc/lynx/extzp.s
+* libsrc/lynx/crt0.s
+* libsrc/lynx/extzp.inc
+
+## \_\_viddma
+
+* libsrc/lynx/tgi/lynx-160-102-16.s
+* libsrc/lynx/extzp.s
+* libsrc/lynx/crt0.s
+* libsrc/lynx/extzp.inc
+
+# pce
+
+## \_\_nmi
+
+* libsrc/pce/irq.s
+* libsrc/pce/crt0.s
diff --git a/libsrc/apple2/allow_lowercase.s b/libsrc/apple2/allow_lowercase.s
new file mode 100644
index 000000000..648276b4c
--- /dev/null
+++ b/libsrc/apple2/allow_lowercase.s
@@ -0,0 +1,23 @@
+;
+; Oliver Schmidt, 2024-08-06
+;
+; unsigned char __fastcall__ allow_lowercase (unsigned char onoff);
+;
+
+ .export _allow_lowercase
+ .import uppercasemask, return0, return1
+
+_allow_lowercase:
+ tax
+ lda values,x
+ ldx uppercasemask
+ sta uppercasemask
+ cpx #$FF
+ beq :+
+ jmp return0
+: jmp return1
+
+ .rodata
+
+values: .byte $DF ; Force uppercase
+ .byte $FF ; Keep lowercase
diff --git a/libsrc/apple2/callmain.s b/libsrc/apple2/callmain.s
new file mode 100644
index 000000000..71a8b5611
--- /dev/null
+++ b/libsrc/apple2/callmain.s
@@ -0,0 +1,75 @@
+;
+; Ullrich von Bassewitz, 2003-03-07
+;
+; Push arguments and call main()
+;
+
+
+ .export callmain, _exit
+ .export __argc, __argv
+
+ .import _main, pushax, done, donelib
+ .import zpsave, rvsave, reset
+
+ .include "zeropage.inc"
+ .include "apple2.inc"
+
+
+;---------------------------------------------------------------------------
+; Setup the stack for main(), then jump to it
+
+callmain:
+ lda __argc
+ ldx __argc+1
+ jsr pushax ; Push argc
+
+ lda __argv
+ ldx __argv+1
+ jsr pushax ; Push argv
+
+ ldy #4 ; Argument size
+ jsr _main
+
+ ; Avoid a re-entrance of donelib. This is also the exit() entry.
+_exit: ldx #exit
+ jsr reset ; Setup RESET vector
+
+ ; Switch in LC bank 2 for R/O in case it was switched out by a RESET.
+ bit $C080
+
+ ; Call the module destructors.
+ jsr donelib
+
+ ; Switch in ROM.
+ bit $C082
+
+ ; Restore the original RESET vector.
+exit: ldx #$02
+: lda rvsave,x
+ sta SOFTEV,x
+ dex
+ bpl :-
+
+ ; Copy back the zero-page stuff.
+ ldx #zpspace-1
+: lda zpsave,x
+ sta sp,x
+ dex
+ bpl :-
+
+ ; ProDOS TechRefMan, chapter 5.2.1:
+ ; "System programs should set the stack pointer to $FF at the
+ ; warm-start entry point."
+ ldx #$FF
+ txs ; Re-init stack pointer
+
+ ; We're done
+ jmp done
+
+;---------------------------------------------------------------------------
+; Data
+
+.data
+__argc: .word 0
+__argv: .addr 0
diff --git a/libsrc/apple2/cputc.s b/libsrc/apple2/cputc.s
index 035b1c047..0a27abacd 100644
--- a/libsrc/apple2/cputc.s
+++ b/libsrc/apple2/cputc.s
@@ -11,6 +11,9 @@
.export _cputcxy, _cputc
.export cputdirect, newline, putchar, putchardirect
.import gotoxy, VTABZ
+ .ifndef __APPLE2ENH__
+ .import uppercasemask
+ .endif
.include "apple2.inc"
@@ -43,7 +46,7 @@ _cputc:
.ifndef __APPLE2ENH__
cmp #$E0 ; Test for lowercase
bcc cputdirect
- and #$DF ; Convert to uppercase
+ and uppercasemask
.endif
cputdirect:
diff --git a/libsrc/apple2/crt0.s b/libsrc/apple2/crt0.s
index c129cdbf8..42e26c27b 100644
--- a/libsrc/apple2/crt0.s
+++ b/libsrc/apple2/crt0.s
@@ -4,10 +4,11 @@
; Startup code for cc65 (Apple2 version)
;
- .export _exit, done, return
+ .export done, return
+ .export zpsave, rvsave, reset
.export __STARTUP__ : absolute = 1 ; Mark as startup
- .import initlib, donelib
+ .import initlib, _exit
.import zerobss, callmain
.import __ONCE_LOAD__, __ONCE_SIZE__ ; Linker generated
.import __LC_START__, __LC_LAST__ ; Linker generated
@@ -33,44 +34,7 @@
jsr zerobss
; Push the command-line arguments; and, call main().
- jsr callmain
-
- ; Avoid a re-entrance of donelib. This is also the exit() entry.
-_exit: ldx #exit
- jsr reset ; Setup RESET vector
-
- ; Switch in LC bank 2 for R/O in case it was switched out by a RESET.
- bit $C080
-
- ; Call the module destructors.
- jsr donelib
-
- ; Switch in ROM.
- bit $C082
-
- ; Restore the original RESET vector.
-exit: ldx #$02
-: lda rvsave,x
- sta SOFTEV,x
- dex
- bpl :-
-
- ; Copy back the zero-page stuff.
- ldx #zpspace-1
-: lda zpsave,x
- sta sp,x
- dex
- bpl :-
-
- ; ProDOS TechRefMan, chapter 5.2.1:
- ; "System programs should set the stack pointer to $FF at the
- ; warm-start entry point."
- ldx #$FF
- txs ; Re-init stack pointer
-
- ; We're done
- jmp done
+ jmp callmain
; ------------------------------------------------------------------------
diff --git a/libsrc/apple2/ser/a2.gs.s b/libsrc/apple2/ser/a2.gs.s
index 3a2db1926..e35c6156b 100644
--- a/libsrc/apple2/ser/a2.gs.s
+++ b/libsrc/apple2/ser/a2.gs.s
@@ -66,34 +66,16 @@ HSType: .res 1 ; Flow-control type
RecvBuf: .res 256 ; Receive buffers: 256 bytes
SendBuf: .res 256 ; Send buffers: 256 bytes
+CurClockSource: .res 1 ; Whether to use BRG or RTxC for clock
+
.data
Opened: .byte $00 ; 1 when opened
Channel: .byte $00 ; Channel B by default
-CurChanIrqFlags:.byte INTR_PENDING_RX_EXT_B
+CurChanIrqFlags:.byte $00
SerFlagOrig: .byte $00
-; Tables used to translate cc65 RS232 params into register values
-; (Ref page 5-18 and 5-19)
-BaudLowTable: .byte $7E ; SER_BAUD_300
- .byte $5E ; SER_BAUD_1200
- .byte $2E ; SER_BAUD_2400
- .byte $16 ; SER_BAUD_4800
- .byte $0A ; SER_BAUD_9600
- .byte $04 ; SER_BAUD_19200
- .byte $01 ; SER_BAUD_38400
- .byte $00 ; SER_BAUD_57600
-
-BaudHighTable: .byte $01 ; SER_BAUD_300
- .byte $00 ; SER_BAUD_1200
- .byte $00 ; SER_BAUD_2400
- .byte $00 ; SER_BAUD_4800
- .byte $00 ; SER_BAUD_9600
- .byte $00 ; SER_BAUD_19200
- .byte $00 ; SER_BAUD_38400
- .byte $00 ; SER_BAUD_57600
-
RxBitTable: .byte %00000000 ; SER_BITS_5, in WR_RX_CTRL (WR3)
.byte %10000000 ; SER_BITS_6 (Ref page 5-7)
.byte %01000000 ; SER_BITS_7
@@ -106,29 +88,65 @@ TxBitTable: .byte %00000000 ; SER_BITS_5, in WR_TX_CTRL (WR5)
.rodata
+ClockMultiplier:.byte %01000000 ; Clock x16 (300-57600bps, WR4, ref page 5-8)
+ .byte %10000000 ; Clock x32 (115200bps, ref page 5-8)
+
+ClockSource: .byte %01010000 ; Use baud rate generator (ch. B) (WR11, page 5-17)
+ .byte %00000000 ; Use RTxC (115200bps) (ch. B)
+ .byte %11010000 ; Use baud rate generator (ch. A)
+ .byte %10000000 ; Use RTxC (115200bps) (ch. A)
+
+BrgEnabled: .byte %00000001 ; Baud rate generator on (WR14, page 5-19)
+ .byte %00000000 ; BRG Off
+
+ChanIrqFlags: .byte %00000101 ; ANDed (RX/special IRQ, ch. B) (page 5-25)
+ .byte %00101000 ; ANDed (RX/special IRQ, ch. A)
+
+ChanIrqMask: .byte %00000111 ; Ch. B IRQ flags mask
+ .byte %00111000 ; Ch. A IRQ flags mask
+
BaudTable: ; bit7 = 1 means setting is invalid
- ; Otherwise refers to the index in
- ; Baud(Low/High)Table
- .byte $FF ; SER_BAUD_45_5
- .byte $FF ; SER_BAUD_50
- .byte $FF ; SER_BAUD_75
- .byte $FF ; SER_BAUD_110
- .byte $FF ; SER_BAUD_134_5
- .byte $FF ; SER_BAUD_150
- .byte $00 ; SER_BAUD_300
- .byte $FF ; SER_BAUD_600
- .byte $01 ; SER_BAUD_1200
- .byte $FF ; SER_BAUD_1800
- .byte $02 ; SER_BAUD_2400
- .byte $FF ; SER_BAUD_3600
- .byte $03 ; SER_BAUD_4800
- .byte $FF ; SER_BAUD_7200
- .byte $04 ; SER_BAUD_9600
- .byte $05 ; SER_BAUD_19200
- .byte $06 ; SER_BAUD_38400
- .byte $07 ; SER_BAUD_57600
- .byte $FF ; SER_BAUD_115200
- .byte $FF ; SER_BAUD_230400
+ ; Indexes cc65 RS232 SER_BAUD enum
+ ; into WR12/13 register values
+ ; (Ref page 5-18 and 5-19)
+ .word $FFFF ; SER_BAUD_45_5
+ .word $FFFF ; SER_BAUD_50
+ .word $FFFF ; SER_BAUD_75
+ .word $FFFF ; SER_BAUD_110
+ .word $FFFF ; SER_BAUD_134_5
+ .word $FFFF ; SER_BAUD_150
+ .word $017E ; SER_BAUD_300
+ .word $FFFF ; SER_BAUD_600
+ .word $005E ; SER_BAUD_1200
+ .word $FFFF ; SER_BAUD_1800
+ .word $002E ; SER_BAUD_2400
+ .word $FFFF ; SER_BAUD_3600
+ .word $0016 ; SER_BAUD_4800
+ .word $FFFF ; SER_BAUD_7200
+ .word $000A ; SER_BAUD_9600
+ .word $0004 ; SER_BAUD_19200
+ .word $0001 ; SER_BAUD_38400
+ .word $0000 ; SER_BAUD_57600
+ .word $0000 ; SER_BAUD_115200 (constant unused at that speed)
+ .word $FFFF ; SER_BAUD_230400
+
+; About the speed selection: either we use the baud rate generator:
+; - Load the time constants from BaudTable into WR12/WR13
+; - Setup the TX/RX clock source to BRG (ClockSource into WR11)
+; - Setup the clock multiplier (WR4)
+; - Enable the baud rate generator (WR14)
+; In this case, the baud rate will be:
+; rate = crystal_clock/(2+BRG_time_constant))/(2*clock_multiplier)
+; Example: (3686400/(2+0x0004)) / (2*16) = 19200 bps
+;
+; Or we don't use the baud rate generator:
+; - Setup the TX/RX clock source to RTxC
+; - Setup the clock multiplier
+; - Disable the baud rate generator
+; - WR12 and 13 are ignored
+; In this case, the baud rate will be:
+; rate = crystal_clock/clock_multiplier
+; Example: 3686400/32 = 115200 bps
StopTable: .byte %00000100 ; SER_STOP_1, in WR_TX_RX_CTRL (WR4)
.byte %00001100 ; SER_STOP_2 (Ref page 5-8)
@@ -156,6 +174,7 @@ SER_FLAG := $E10104
; ------------------------------------------------------------------------
; Channels
+
CHANNEL_B = 0
CHANNEL_A = 1
@@ -180,7 +199,6 @@ RX_CTRL_OFF = %11111110 ; ANDed,Rx disabled
WR_TX_RX_CTRL = 4
RR_TX_RX_STATUS = 4
-TX_RX_CLOCK_MUL = %01000000 ; Clock x16 (Ref page 5-8)
WR_TX_CTRL = 5 ; (Ref page 5-9)
RR_TX_STATUS = 5 ; Corresponding status register
@@ -197,15 +215,11 @@ MASTER_IRQ_MIE_RST = %00001010 ; STA'd
MASTER_IRQ_SET = %00011001 ; STA'd
WR_CLOCK_CTRL = 11 ; (Ref page 5-17)
-CLOCK_CTRL_CH_A = %11010000
-CLOCK_CTRL_CH_B = %01010000
WR_BAUDL_CTRL = 12 ; (Ref page 5-18)
WR_BAUDH_CTRL = 13 ; (Ref page 5-19)
WR_MISC_CTRL = 14 ; (Ref page 5-19)
-MISC_CTRL_RATE_GEN_ON = %00000001 ; ORed
-MISC_CTRL_RATE_GEN_OFF = %11111110 ; ANDed
WR_IRQ_CTRL = 15 ; (Ref page 5-20)
IRQ_CLEANUP_EIRQ = %00001000
@@ -220,13 +234,8 @@ IRQ_RX = %00100000
IRQ_SPECIAL = %01100000
RR_INTR_PENDING_STATUS = 3 ; (Ref page 5-25)
-INTR_PENDING_RX_EXT_A = %00101000 ; ANDed (RX or special IRQ)
-INTR_PENDING_RX_EXT_B = %00000101 ; ANDed (RX or special IRQ)
INTR_IS_RX = %00100100 ; ANDed (RX IRQ, channel A or B)
-SER_FLAG_CH_A = %00111000
-SER_FLAG_CH_B = %00000111
-
.code
; Read register value to A.
@@ -329,6 +338,15 @@ IIgs:
: txa ; Promote char return value
rts
+getClockSource:
+ .assert SER_PARAMS::BAUDRATE = 0, error
+ lda (ptr1) ; Baudrate index - cc65 value
+ cmp #SER_BAUD_115200
+ lda #$00
+ adc #$00
+ sta CurClockSource ; 0 = BRG, 1 = RTxC
+ rts
+
;----------------------------------------------------------------------------
; SER_OPEN: A pointer to a ser_params structure is passed in ptr1.
; Must return an SER_ERR_xx code in a/x.
@@ -360,11 +378,13 @@ SER_OPEN:
ldy #RR_INIT_STATUS ; Hit rr0 once to sync up
jsr readSSCReg
- ldy #WR_MISC_CTRL ; Turn everything off
+ ldy #WR_MISC_CTRL ; WR14: Turn everything off
lda #$00
jsr writeSCCReg
- ldy #SER_PARAMS::STOPBITS
+ jsr getClockSource ; Should we use BRG or RTxC?
+
+ ldy #SER_PARAMS::STOPBITS ; WR4 setup: clock mult., stop & parity
lda (ptr1),y ; Stop bits
tay
lda StopTable,y ; Get value
@@ -377,36 +397,33 @@ SER_OPEN:
ora ParityTable,y ; Get value
bmi InvParam
- ora #TX_RX_CLOCK_MUL
+ ldy CurClockSource ; Clock multiplier
+ ora ClockMultiplier,y
- ldy #WR_TX_RX_CTRL ; Setup stop & parity bits
- jsr writeSCCReg
+ ldy #WR_TX_RX_CTRL
+ jsr writeSCCReg ; End of WR4 setup
+ ldy CurClockSource ; WR11 setup: clock source
cpx #CHANNEL_B
- bne ClockA
-ClockB:
+ beq SetClock
+ iny ; Shift to get correct ClockSource val
+ iny ; depending on our channel
+
+SetClock:
+ lda ClockSource,y
ldy #WR_CLOCK_CTRL
- lda #CLOCK_CTRL_CH_B
- jsr writeSCCReg
+ jsr writeSCCReg ; End of WR11 setup
- lda #INTR_PENDING_RX_EXT_B ; Store which IRQ bits we'll check
- sta CurChanIrqFlags
-
- bra SetBaud
-ClockA:
- ldy #WR_CLOCK_CTRL
- lda #CLOCK_CTRL_CH_A
- jsr writeSCCReg
-
- lda #INTR_PENDING_RX_EXT_A ; Store which IRQ bits we'll check
+ lda ChanIrqFlags,x ; Store which IRQ bits we'll check
sta CurChanIrqFlags
SetBaud:
- ldy #SER_PARAMS::BAUDRATE
- lda (ptr1),y ; Baudrate index - cc65 value
+ .assert SER_PARAMS::BAUDRATE = 0, error
+ lda (ptr1) ; Baudrate index - cc65 value
+ asl
tay
- lda BaudTable,y ; Get chip value from Low/High tables
+ lda BaudTable,y ; Get low byte of register value
bpl BaudOK ; Verify baudrate is supported
InvParam:
@@ -415,59 +432,57 @@ InvParam:
bra SetupOut
BaudOK:
- tay
-
- lda BaudLowTable,y ; Get low byte
-
- phy
- ldy #WR_BAUDL_CTRL
- jsr writeSCCReg
+ phy ; WR12 setup: BRG time constant, low byte
+ ldy #WR_BAUDL_CTRL ; Setting WR12 & 13 is useless if we're using
+ jsr writeSCCReg ; RTxC, but doing it anyway makes code smaller
ply
- lda BaudHighTable,y ; Get high byte
+ iny
+ lda BaudTable,y ; WR13 setup: BRG time constant, high byte
ldy #WR_BAUDH_CTRL
jsr writeSCCReg
+ ldy CurClockSource ; WR14 setup: BRG enabling
+ lda BrgEnabled,y
ldy #WR_MISC_CTRL ; Time to turn this thing on
- lda #MISC_CTRL_RATE_GEN_ON
jsr writeSCCReg
- ldy #SER_PARAMS::DATABITS
- lda (ptr1),y ; Data bits
+ ldy #SER_PARAMS::DATABITS ; WR3 setup: RX data bits
+ lda (ptr1),y
tay
- lda RxBitTable,y ; Data bits for RX
- ora #RX_CTRL_ON ; and turn RX on
+ lda RxBitTable,y
+ ora #RX_CTRL_ON ; and turn receiver on
phy
ldy #WR_RX_CTRL
- jsr writeSCCReg
+ jsr writeSCCReg ; End of WR3 setup
ply
- lda TxBitTable,y ; Data bits for TX
- ora #TX_CTRL_ON ; and turn TX on
- and #TX_DTR_ON
+ lda TxBitTable,y ; WR5 setup: TX data bits
+ ora #TX_CTRL_ON ; and turn transmitter on
+ and #TX_DTR_ON ; and turn DTR on
sta RtsOff ; Save value for flow control
- ora #TX_RTS_ON
+ ora #TX_RTS_ON ; and turn RTS on
ldy #WR_TX_CTRL
- jsr writeSCCReg
+ jsr writeSCCReg ; End of WR5 setup
- ldy #WR_IRQ_CTRL
+ ldy #WR_IRQ_CTRL ; WR15 setup: IRQ
lda #IRQ_CLEANUP_EIRQ
jsr writeSCCReg
- ldy #WR_INIT_CTRL ; Clear ext status (write twice)
+ ldy #WR_INIT_CTRL ; WR0 setup: clear existing IRQs
lda #INIT_CTRL_CLEAR_EIRQ
- jsr writeSCCReg
+ jsr writeSCCReg ; Clear (write twice)
jsr writeSCCReg
- ldy #WR_TX_RX_MODE_CTRL ; Activate RX IRQ
+ ldy #WR_TX_RX_MODE_CTRL ; WR1 setup: Activate RX IRQ
lda #TX_RX_MODE_RXIRQ
jsr writeSCCReg
- lda SCCBREG ; Activate master IRQ
+ lda SCCBREG ; WR9 setup: Activate master IRQ
ldy #WR_MASTER_IRQ_RST
lda #MASTER_IRQ_SET
jsr writeSCCReg
@@ -475,14 +490,7 @@ BaudOK:
lda SER_FLAG ; Get SerFlag's current value
sta SerFlagOrig ; and save it
- cpx #CHANNEL_B
- bne IntA
-IntB:
- ora #SER_FLAG_CH_B ; Inform firmware we want channel B IRQs
- bra StoreFlag
-IntA:
- ora #SER_FLAG_CH_A ; Inform firmware we want channel A IRQs
-StoreFlag:
+ ora ChanIrqMask,x ; Tell firmware which channel IRQs we want
sta SER_FLAG
ldy #$01 ; Mark port opened
diff --git a/libsrc/apple2/ser/a2.ssc.s b/libsrc/apple2/ser/a2.ssc.s
index c8aa6e9a5..88dc4572c 100644
--- a/libsrc/apple2/ser/a2.ssc.s
+++ b/libsrc/apple2/ser/a2.ssc.s
@@ -121,7 +121,7 @@ BaudTable: ; Table used to translate RS232 baudrate param
.byte $0F ; SER_BAUD_19200
.byte $FF ; SER_BAUD_38400
.byte $FF ; SER_BAUD_57600
- .byte $FF ; SER_BAUD_115200
+ .byte $00 ; SER_BAUD_115200
.byte $FF ; SER_BAUD_230400
BitTable: ; Table used to translate RS232 databits param
@@ -302,6 +302,7 @@ HandshakeOK:
lda (ptr1),y ; Baudrate index
tay
lda BaudTable,y ; Get 6551 value
+ sta tmp2 ; Backup for IRQ setting
bpl BaudOK ; Check that baudrate is supported
lda #SER_ERR_BAUD_UNAVAIL
@@ -332,8 +333,13 @@ BaudOK: sta tmp1
ora #%00000001 ; Set DTR active
sta RtsOff ; Store value to easily handle flow control later
- ora #%00001000 ; Enable receive interrupts (RTS low)
- sta ACIA_CMD,x
+
+ ora #%00001010 ; Disable interrupts and set RTS low
+
+ ldy tmp2 ; Don't enable IRQs if 115200bps
+ beq :+
+ and #%11111101 ; Enable receive IRQs
+: sta ACIA_CMD,x
; Done
stx Index ; Mark port as open
diff --git a/libsrc/apple2/uppercasemask.s b/libsrc/apple2/uppercasemask.s
new file mode 100644
index 000000000..8b993bb1e
--- /dev/null
+++ b/libsrc/apple2/uppercasemask.s
@@ -0,0 +1,9 @@
+;
+; Oliver Schmidt, 2024-08-06
+;
+
+ .export uppercasemask
+
+ .data
+
+uppercasemask: .byte $DF ; Convert to uppercase
diff --git a/libsrc/apple2/write.s b/libsrc/apple2/write.s
index 7b50d0705..5fb51cca6 100644
--- a/libsrc/apple2/write.s
+++ b/libsrc/apple2/write.s
@@ -7,6 +7,9 @@
.export _write
.import rwprolog, rwcommon, rwepilog
.import COUT
+ .ifndef __APPLE2ENH__
+ .import uppercasemask
+ .endif
.include "zeropage.inc"
.include "errno.inc"
@@ -84,7 +87,7 @@ next: lda (ptr1),y
.ifndef __APPLE2ENH__
cmp #$E0 ; Test for lowercase
bcc output
- and #$DF ; Convert to uppercase
+ and uppercasemask
.endif
output: jsr COUT ; Preserves X and Y
diff --git a/libsrc/atari7800/joy/atari7800-stdjoy.s b/libsrc/atari7800/joy/atari7800-stdjoy.s
index 59f656ada..c24e87e29 100644
--- a/libsrc/atari7800/joy/atari7800-stdjoy.s
+++ b/libsrc/atari7800/joy/atari7800-stdjoy.s
@@ -53,13 +53,20 @@ JOY_COUNT = 2 ; Number of joysticks we support
; Must return an JOY_ERR_xx code in a/x.
;
+PB2 = $04 ; Joystick 0
+PB4 = $10 ; Joystick 1
+
INSTALL:
; Assume 7800 2-button controller, can change
; to 2600 1-button later
- lda #$14
- sta CTLSWB ; enable 2-button 7800 controller 1: set pin 6 to output
+ lda #(PB2 | PB4)
+ ; enable 2-button 7800 controllers on both ports
+ ; by setting PB2 and PB4 to output
+ sta CTLSWB
+ ; enable 2-button 7800 controllers by setting
+ ; the outputs to 0; (INPT4 and INPT5) high
ldy #$00
- sty SWCHB ; enable 2-button 7800 controller 2: pull pin 6 (INPT4) high
+ sty SWCHB
reset:
lda #JOY_ERR_OK
@@ -88,6 +95,28 @@ COUNT:
; ------------------------------------------------------------------------
; READ: Read a particular joystick passed in A for 2 fire buttons.
+readdualbuttons0:
+ ldy #0 ; ........
+ bit INPT0 ; Check for right button
+ bpl L1
+ ldy #2 ; ......2.
+L1: bit INPT1 ; Check for left button
+ bpl L2
+ iny ; ......21
+L2: tya
+ rts
+
+readdualbuttons1:
+ ldy #0 ; ........
+ bit INPT2 ; Check for right button
+ bpl L1
+ ldy #2 ; ......2.
+L3: bit INPT3 ; Check for left button
+ bpl L2
+ iny ; ......21
+L4: tya
+ rts
+
readbuttons:
; Y has joystick of interest 0/1
; return value:
@@ -97,42 +126,48 @@ readbuttons:
; $03: both buttons
; preserves X
tya
- beq L5
+ beq readbuttons0
+readbuttons1:
; Joystick 1 processing
- ; 7800 joystick 1 buttons
- ldy #0 ; ........
- bit INPT2 ; Check for right button
- bpl L1
- ldy #2 ; ......2.
-L1: bit INPT3 ;Check for left button
- bpl L2
- iny ; ......21
-L2: tya
- bne L4 ; 7800 mode joystick worked
- ; 2600 Joystick 1
+ ; Start by checking for single button 2600 joystick
bit INPT5
- bmi L4
-L3: iny ; .......1
- lda #0 ; Fallback to 2600 joystick mode
- sta CTLSWB
-L4: tya ; ......21
+ bpl singlebtn1detected
+ jmp readdualbuttons1
+singlebtn1detected:
+ ; Single button joystick detected but could be dual
+ jsr readdualbuttons1
+ bne L5 ; It was a dual button press
+ ; It was a single button press
+ bit INPT5
+ bmi L5
+ iny ; .......1
+ lda #PB4 ; Joystick 1 is a single button unit
+ clc
+ adc SWCHB
+ sta SWCHB ; Cut power from the dual button circuit
+L5: tya ; ......21
rts
-L5: ; Joystick 0 processing
- ; 7800 joystick 0 buttons
- ldy #0 ; ........
- bit INPT0 ; Check for right button
- bpl L6
- ldy #2 ; ......2.
-L6: bit INPT1 ;Check for left button
- bpl L7
- iny ; ......21
-L7: tya
- bne L4 ; 7800 mode joystick worked
- ; 2600 Joystick 0
+readbuttons0:
+ ; Joystick 0 processing
+ ; Start by checking for single button 2600 joystick
bit INPT4
- bmi L4
- bpl L3
+ bpl singlebtn0detected
+ jmp readdualbuttons0
+singlebtn0detected:
+ ; Single button joystick detected but could be dual
+ jsr readdualbuttons0
+ bne L6 ; It was a dual button press
+ ; It was a single button press
+ bit INPT4
+ bmi L6
+ iny ; .......1
+ lda #PB2 ; Joystick 0 is a single button unit
+ clc
+ adc SWCHB
+ sta SWCHB ; Cut power from the dual button circuit
+L6: tya ; ......21
+ rts
READ:
tay ; Store joystick 0/1 in Y
diff --git a/libsrc/atmos/waitvsync.s b/libsrc/atmos/waitvsync.s
new file mode 100644
index 000000000..85e50a795
--- /dev/null
+++ b/libsrc/atmos/waitvsync.s
@@ -0,0 +1,18 @@
+;
+; Written by Stefan Haubenthal , requires VSync hack
+;
+; void waitvsync (void);
+;
+
+ .export _waitvsync
+
+ .include "atmos.inc"
+
+.proc _waitvsync
+
+ lda #%00010000 ; CB1
+wait: and VIA::PRA2
+ bne wait
+ rts
+
+.endproc
diff --git a/libsrc/c128/waitvsync.s b/libsrc/c128/waitvsync.s
index e4bbbf7c9..573f574a7 100644
--- a/libsrc/c128/waitvsync.s
+++ b/libsrc/c128/waitvsync.s
@@ -23,8 +23,8 @@ _waitvsync:
@c80:
;FIXME: do we have to switch banks?
+ lda #$20
@l3:
- lda VDC_INDEX
- and #$20
+ and VDC_INDEX
beq @l3
rts
diff --git a/libsrc/common/stpcpy.s b/libsrc/common/stpcpy.s
new file mode 100644
index 000000000..c8a10db94
--- /dev/null
+++ b/libsrc/common/stpcpy.s
@@ -0,0 +1,22 @@
+;
+; Colin Leroy-Mira, 4 Sept. 2024
+;
+; char* stpcpy (char* dest, const char* src);
+;
+
+ .export _stpcpy
+ .import _strcpy
+
+ .importzp tmp1, ptr2
+
+_stpcpy:
+ jsr _strcpy
+
+ ldx ptr2+1 ; Load dest pointer's last high byte
+ tya ; Get the last offset strcpy wrote to
+
+ clc
+ adc ptr2 ; Add to low byte value
+ bcc :+
+ inx
+: rts ; Return pointer to dest's terminator
diff --git a/libsrc/common/strcasestr.s b/libsrc/common/strcasestr.s
new file mode 100644
index 000000000..58364f419
--- /dev/null
+++ b/libsrc/common/strcasestr.s
@@ -0,0 +1,95 @@
+;
+; Ullrich von Bassewitz, 11.12.1998
+;
+; char* strcasestr (const char* haystack, const char* needle);
+;
+
+ .export _strcasestr
+ .import popptr1, return0, tolowerdirect
+ .importzp ptr1, ptr2, ptr3, ptr4, tmp1, tmp2, tmp3, tmp4
+ .include "ctype.inc"
+
+ .segment "LOWCODE"
+
+_strcasestr:
+ sta ptr2 ; Save needle
+ stx ptr2+1
+ sta ptr4 ; Setup temp copy for later
+
+ jsr popptr1 ; Get haystack to ptr1
+
+; If needle is empty, return haystack
+
+ ; ldy #$00 Y=0 guaranteed by popptr1
+ lda (ptr2),y ; Get first byte of needle
+ beq @Found ; Needle is empty --> we're done
+
+; Search for the beginning of the string (this is not an optimal search
+; strategy [in fact, it's pretty dumb], but it's simple to implement).
+
+ jsr tolowerdirect ; Lowercase
+ sta tmp1 ; Save start of needle
+@L1: lda (ptr1),y ; Get next char from haystack
+ beq @NotFound ; Jump if end
+
+ jsr tolowerdirect ; Lowercase
+ cmp tmp1 ; Start of needle found?
+ beq @L2 ; Jump if so
+ iny ; Next char
+ bne @L1
+ inc ptr1+1 ; Bump high byte
+ bne @L1 ; Branch always
+
+; We found the start of needle in haystack
+
+@L2: tya ; Get offset
+ clc
+ adc ptr1
+ sta ptr1 ; Make ptr1 point to start
+ bcc @L3
+ inc ptr1+1
+
+; ptr1 points to the start of needle in haystack now. Setup temporary pointers for the
+; search. The low byte of ptr4 is already set.
+
+@L3: sta ptr3
+ lda ptr1+1
+ sta ptr3+1
+ lda ptr2+1
+ sta ptr4+1
+ ldy #1 ; First char is identical, so start on second
+
+; Do the compare
+
+@L4: lda (ptr4),y ; Get char from needle
+ beq @Found ; Jump if end of needle (-> found)
+
+ jsr tolowerdirect ; Lowercase
+ sta tmp2
+
+ lda (ptr3),y ; Compare with haystack
+
+ jsr tolowerdirect ; Lowercase
+ cmp tmp2
+ bne @L5 ; Jump if not equal
+ iny ; Next char
+ bne @L4
+ inc ptr3+1
+ inc ptr4+1 ; Bump hi byte of pointers
+ bne @L4 ; Next char (branch always)
+
+; The strings did not compare equal, search next start of needle
+
+@L5: ldy #1 ; Start after this char
+ bne @L1 ; Branch always
+
+; We found the start of needle
+
+@Found: lda ptr1
+ ldx ptr1+1
+ rts
+
+; We reached end of haystack without finding needle
+
+@NotFound:
+ jmp return0 ; return NULL
diff --git a/libsrc/common/strcpy.s b/libsrc/common/strcpy.s
index 77b39fe76..9a100f540 100644
--- a/libsrc/common/strcpy.s
+++ b/libsrc/common/strcpy.s
@@ -25,6 +25,9 @@ L1: lda (ptr1),y
inc ptr2+1
bne L1
-L9: lda ptr2 ; X still contains high byte
- rts
+L9: lda ptr2 ; X still contains dest's original high byte
+ ; On exit, we want AX to be dest (as this is what strcpy returns).
+ ; We also want (ptr2),y to still point to dest's terminator, as this
+ ; is used by stpcpy().
+ rts
diff --git a/libsrc/common/strstr.s b/libsrc/common/strstr.s
index 84f633245..691e5ba5c 100644
--- a/libsrc/common/strstr.s
+++ b/libsrc/common/strstr.s
@@ -82,14 +82,3 @@ _strstr:
lda #$00 ; return NULL
tax
rts
-
-
-
-
-
-
-
-
-
-
-
diff --git a/libsrc/common/time.s b/libsrc/common/time.s
index 40b470f5b..4092e71c6 100644
--- a/libsrc/common/time.s
+++ b/libsrc/common/time.s
@@ -6,7 +6,7 @@
.export _time
- .import decsp1, ldeaxi
+ .import pusha, ldeaxi
.importzp ptr1, sreg, tmp1, tmp2
.include "time.inc"
@@ -22,54 +22,50 @@
; Get the time (machine dependent)
- jsr decsp1
+ .assert timespec::tv_sec = 0, error
+ lda #CLOCK_REALTIME
+ jsr pusha
lda #time
jsr _clock_gettime
- sta tmp2
- lda #time
- .assert timespec::tv_sec = 0, error
- jsr ldeaxi
- sta tmp1 ; Save low byte of result
+
+; _clock_gettime returns 0 on success and -1 on error. Check that.
+
+ inx ; Did _clock_gettime return -1?
+ bne @L2 ; Jump if not
+
+; We had an error so invalidate time. A contains $FF.
+
+ ldy #3
+@L1: sta time,y
+ dey
+ bpl @L1
; Restore timep and check if it is NULL
- pla
+@L2: pla
sta ptr1+1
pla
sta ptr1 ; Restore timep
ora ptr1+1 ; timep == 0?
- beq @L1
+ beq @L4
; timep is not NULL, store the result there
ldy #3
- lda sreg+1
+@L3: lda time,y
sta (ptr1),y
dey
- lda sreg
- sta (ptr1),y
- dey
- txa
- sta (ptr1),y
- dey
- lda tmp1
- sta (ptr1),y
+ bpl @L3
-; If the result is != 0, return -1
+; Load the final result.
-@L1: lda tmp2
- beq @L2
-
- tax
- sta sreg
+@L4: lda time+3
sta sreg+1
- rts
-
-; Reload the low byte of the result and return
-
-@L2: lda tmp1
+ lda time+2
+ sta sreg
+ ldx time+1
+ lda time
rts
.endproc
diff --git a/libsrc/common/tolower.s b/libsrc/common/tolower.s
index 828be1cb1..9c143f1ce 100644
--- a/libsrc/common/tolower.s
+++ b/libsrc/common/tolower.s
@@ -10,19 +10,20 @@
; int tolower (int c);
;
- .export _tolower
+ .export _tolower, tolowerdirect
.include "ctype.inc"
.import ctypemaskdirect
_tolower:
cpx #$00 ; out of range?
- bne @L2 ; if so, return the argument unchanged
- tay ; save char
+ bne out ; if so, return the argument unchanged
+tolowerdirect:
+ pha ; save char
jsr ctypemaskdirect ; get character classification
and #CT_UPPER ; upper case char?
beq @L1 ; jump if no
- tya ; restore char
+ pla ; restore char
adc #<('a'-'A') ; make lower case char (ctypemaskdirect ensures carry clear)
rts
-@L1: tya ; restore char
-@L2: rts
+@L1: pla ; restore char
+out: rts
diff --git a/libsrc/cx16/tgi/cx640p1.s b/libsrc/cx16/tgi/cx640p1.s
new file mode 100644
index 000000000..287160f6b
--- /dev/null
+++ b/libsrc/cx16/tgi/cx640p1.s
@@ -0,0 +1,675 @@
+;
+; Graphics driver for the 640 pixels across, 480 pixels down, 2 color mode
+; on the Commander X16
+;
+; 2024-06-11, Scott Hutter
+; Based on code by Greg King
+;
+
+ .include "zeropage.inc"
+
+ .include "tgi-kernel.inc"
+ .include "tgi-error.inc"
+
+ .include "cbm_kernal.inc"
+ .include "cx16.inc"
+
+ .macpack generic
+ .macpack module
+
+
+; ------------------------------------------------------------------------
+; Header. Includes jump table and constants.
+
+ module_header _cx640p1_tgi ; 640 pixels across, 1 pixel per bit
+
+; First part of the header is a structure that has a signature,
+; and defines the capabilities of the driver.
+
+ .byte $74, $67, $69 ; ASCII "tgi"
+ .byte TGI_API_VERSION ; TGI API version number
+ .addr $0000 ; Library reference
+ .word 640 ; X resolution
+ .word 480 ; Y resolution
+ .byte 2 ; Number of drawing colors
+ .byte 0 ; Number of screens available
+ .byte 8 ; System font X size
+ .byte 8 ; System font Y size
+ .word $0100 ; Aspect ratio (based on VGA display)
+ .byte 0 ; TGI driver flags
+
+; Next, comes the jump table. Currently, all entries must be valid,
+; and may point to an RTS for test versions (function not implemented).
+
+ .addr INSTALL
+ .addr UNINSTALL
+ .addr INIT
+ .addr DONE
+ .addr GETERROR
+ .addr CONTROL
+ .addr CLEAR
+ .addr SETVIEWPAGE
+ .addr SETDRAWPAGE
+ .addr SETCOLOR
+ .addr SETPALETTE
+ .addr GETPALETTE
+ .addr GETDEFPALETTE
+ .addr SETPIXEL
+ .addr GETPIXEL
+ .addr LINE
+ .addr BAR
+ .addr TEXTSTYLE
+ .addr OUTTEXT
+
+
+; ------------------------------------------------------------------------
+; Constant
+
+
+
+; ------------------------------------------------------------------------
+; Data.
+
+; Variables mapped to the zero page segment variables. Some of these are
+; used for passing parameters to the driver.
+
+X1 = ptr1
+Y1 = ptr2
+X2 = ptr3
+Y2 = ptr4
+
+ADDR = tmp1 ; ADDR+1,2,3
+
+TEMP = tmp3
+TEMP2 = tmp4 ; HORLINE
+TEMP3 = sreg ; HORLINE
+
+
+; Absolute variables used in the code
+
+.bss
+
+; The colors are indicies into a TGI palette. The TGI palette is indicies into
+; VERA's palette. Vera's palette is a table of Red, Green, and Blue levels.
+; The first 16 RGB elements mimic the Commodore 64's colors.
+
+SCRBASE: .res 1 ; High byte of screen base
+BITMASK: .res 1 ; $00 = clear, $FF = set pixels
+
+defpalette: .res 2
+palette: .res 2
+
+color: .res 1 ; Stroke and fill index
+text_mode: .res 1 ; Old text mode
+
+tempX: .res 2
+tempY: .res 2
+ERR2: .res 1
+ERR: .res 1
+SY: .res 1
+SX: .res 1
+DY: .res 1
+DX: .res 1
+CURRENT_Y: .res 2
+CURRENT_X: .res 2
+
+.data
+
+ERROR: .byte TGI_ERR_OK ; Error code
+
+
+; Constants and tables
+
+.rodata
+
+veracolors:
+col_black: .byte %00000000, %00000000
+col_white: .byte %11111111, %00001111
+col_red: .byte %00000000, %00001000
+col_cyan: .byte %11111110, %00001010
+col_purple: .byte %01001100, %00001100
+col_green: .byte %11000101, %00000000
+col_blue: .byte %00001010, %00000000
+col_yellow: .byte %11100111, %00001110
+col_orange: .byte %10000101, %00001101
+col_brown: .byte %01000000, %00000110
+col_lred: .byte %01110111, %00001111
+col_gray1: .byte %00110011, %00000011
+col_gray2: .byte %01110111, %00000111
+col_lgreen: .byte %11110110, %00001010
+col_lblue: .byte %10001111, %00000000
+col_gray3: .byte %10111011, %00001011
+
+; Bit masks for setting pixels
+bitMasks1:
+ .byte %10000000, %01000000, %00100000, %00010000
+ .byte %00001000, %00000100, %00000010, %00000001
+bitMasks2:
+ .byte %01111111, %10111111, %11011111, %11101111
+ .byte %11110111, %11111011, %11111101, %11111110
+
+
+.code
+
+; ------------------------------------------------------------------------
+; INSTALL routine. Is called after the driver is loaded into memory. May
+; initialize anything that has to be done just once. Is probably empty
+; most of the time.
+;
+; Must set an error code: NO
+
+INSTALL:
+; Create the default palette.
+ lda #$00
+ sta defpalette
+ lda #$01
+ sta defpalette+1
+
+ ; Fall through.
+
+; ------------------------------------------------------------------------
+; UNINSTALL routine. Is called before the driver is removed from memory. May
+; clean up anything done by INSTALL, but is probably empty most of the time.
+;
+; Must set an error code: NO
+
+UNINSTALL:
+ rts
+
+; ------------------------------------------------------------------------
+; INIT: Changes an already installed device from text mode to graphics
+; mode.
+; Note that INIT/DONE may be called multiple times while the driver
+; is loaded, while INSTALL is called only once; so, any code that is needed
+; to initiate variables and so on must go here. Setting the palette is not
+; needed because that is called by the graphics kernel later.
+; The graphics kernel never will call INIT when a graphics mode already is
+; active, so there is no need to protect against that.
+;
+; Must set an error code: YES
+
+INIT: stz ERROR ; #TGI_ERR_OK
+
+; Save the current text mode.
+
+ sec
+ jsr SCREEN_MODE
+ sta text_mode
+
+; Switch into (640 x 480 x 2 bpp) graphics mode.
+
+ lda #%00000000 ; DCSEL = 0, VRAM port 1
+ sta VERA::CTRL
+ lda #%00100001 ; Disable sprites, layer 1 enable, VGA
+ sta VERA::DISP::VIDEO
+ lda #%00000100 ; Bitmap mode enable
+ sta VERA::L1::CONFIG
+ lda #%00000001 ; Tile width 640
+ sta VERA::L1::TILE_BASE
+ rts
+
+; ------------------------------------------------------------------------
+; DONE: Will be called to switch the graphics device back into text mode.
+; The graphics kernel never will call DONE when no graphics mode is active,
+; so there is no need to protect against that.
+;
+; Must set an error code: NO
+
+DONE:
+ jsr CINT
+ lda text_mode
+ clc
+ jmp SCREEN_MODE
+
+; ------------------------------------------------------------------------
+; GETERROR: Return the error code in .A, and clear it.
+
+GETERROR:
+ lda ERROR
+ stz ERROR
+ rts
+
+; ------------------------------------------------------------------------
+; CONTROL: Platform-/driver-specific entry point.
+;
+; Must set an error code: YES
+
+CONTROL:
+ lda #TGI_ERR_INV_FUNC
+ sta ERROR
+ rts
+
+; ------------------------------------------------------------------------
+; CLEAR: Clear the screen.
+;
+; Must set an error code: NO
+
+CLEAR:
+ .scope inner
+
+ ; set up DCSEL=2
+ lda #(2 << 1)
+ sta VERA::CTRL
+
+ ; set cache writes
+ lda #$40
+ tsb VERA::DISP::VIDEO ; VERA_FX_CTRL when DCSEL=2
+
+ ; set FX cache to all zeroes
+ lda #(6 << 1)
+ sta VERA::CTRL
+
+ lda #$00
+ sta VERA::DISP::VIDEO
+ sta VERA::DISP::HSCALE
+ sta VERA::DISP::VSCALE
+ sta VERA::DISP::FRAME
+
+ stz VERA::CTRL
+ ; set address and increment for bitmap area
+ stz VERA::ADDR
+ stz VERA::ADDR + 1
+ lda #$30 ; increment +4
+ sta VERA::ADDR + 2
+
+ ldy #$F0
+@blank_outer:
+ ldx #$0A
+@blank_loop:
+
+ .repeat 8
+ stz VERA::DATA0
+ .endrep
+
+ dex
+ bne @blank_loop
+ dey
+ bne @blank_outer
+
+ ; set up DCSEL=2
+ lda #(2 << 1)
+ sta VERA::CTRL
+
+ ; set FX off (cache write bit 1 -> 0)
+ stz VERA::DISP::VIDEO ; VERA_FX_CTRL when DCSEL=2
+ stz VERA::CTRL
+
+ .endscope
+ rts
+
+
+; ------------------------------------------------------------------------
+; SETVIEWPAGE: Set the visible page. Called with the new page in .A (0..n-1).
+; The page number already is checked to be valid by the graphics kernel.
+;
+; Must set an error code: NO (will be called only if page OK)
+
+SETVIEWPAGE:
+
+ ; Fall through.
+
+; ------------------------------------------------------------------------
+; SETDRAWPAGE: Set the drawable page. Called with the new page in .A (0..n-1).
+; The page number already is checked to be valid by the graphics kernel.
+;
+; Must set an error code: NO (will be called only if page OK)
+
+SETDRAWPAGE:
+ rts
+
+; ------------------------------------------------------------------------
+; SETPALETTE: Set the palette (not available with all drivers/hardware).
+; A pointer to the palette is passed in ptr1. Must set an error if palettes
+; are not supported
+;
+; Must set an error code: YES
+
+SETPALETTE:
+ stz ERROR ; #TGI_ERR_OK
+ ldy #$01 ; Palette size of 2 colors
+@L1: lda (ptr1),y ; Copy the palette
+ sta palette,y
+ dey
+ bpl @L1
+
+ ; set background color from palette color 0
+ lda #$00
+ sta VERA::ADDR
+ lda #$FA
+ sta VERA::ADDR+1
+ lda #$01
+ sta VERA::ADDR+2 ; write color RAM @ $1FA00
+
+ lda palette
+ asl
+ tay
+ lda veracolors,y
+ sta VERA::DATA0
+
+ inc VERA::ADDR ; $1FA01
+
+ lda palette
+ asl
+ tay
+ iny ; second byte of color
+ lda veracolors,y
+ sta VERA::DATA0
+
+ ; set foreground color from palette color 1
+ inc VERA::ADDR ; $1FA02
+
+ lda palette+1
+ asl
+ tay
+ lda veracolors,y
+ sta VERA::DATA0
+
+ inc VERA::ADDR ; $1FA03
+
+ lda palette+1
+ asl
+ tay
+ iny ; second byte of color
+ lda veracolors,y
+ sta VERA::DATA0
+ rts
+
+; ------------------------------------------------------------------------
+; SETCOLOR: Set the drawing color (in .A). The new color already is checked
+; to be in a valid range (0..maxcolor).
+;
+; Must set an error code: NO (will be called only if color OK)
+
+SETCOLOR:
+ tax
+ beq @L1
+ lda #$FF
+@L1: sta BITMASK
+ stx color
+ rts
+
+; ------------------------------------------------------------------------
+; GETPALETTE: Return the current palette in .XA. Even drivers that cannot
+; set the palette should return the default palette here, so there's no
+; way for this function to fail.
+;
+; Must set an error code: NO
+
+GETPALETTE:
+ lda #palette
+ rts
+
+; ------------------------------------------------------------------------
+; GETDEFPALETTE: Return the default palette for the driver in .XA. All
+; drivers should return something reasonable here, even drivers that don't
+; support palettes, otherwise the caller has no way to determine the colors
+; of the (not changable) palette.
+;
+; Must set an error code: NO (all drivers must have a default palette)
+
+GETDEFPALETTE:
+ lda #defpalette
+ rts
+
+; ------------------------------------------------------------------------
+; SETPIXEL: Draw one pixel at X1/Y1 = ptr1/ptr2 with the current drawing
+; color. The co-ordinates passed to this function never are outside the
+; visible screen area, so there is no need for clipping inside this function.
+;
+; Must set an error code: NO
+
+SETPIXEL:
+ jsr CALC
+
+ stx TEMP
+
+ lda ADDR
+ ldy ADDR+1
+ ldx #$00
+
+ sta VERA::ADDR
+ sty VERA::ADDR + 1
+ stx VERA::ADDR + 2
+
+ ldx TEMP
+
+ lda BITMASK
+ beq @ahead
+
+ ; if BITMASK = $00, white is line color
+ ; Set the bit in the byte at VERA_DATA0
+ lda VERA::DATA0 ; Load the byte at memory address
+ ora bitMasks1,X ; OR with the bit mask
+ sta VERA::DATA0 ; Store back the modified byte
+ rts
+
+@ahead:
+ ; if BITMASK = $FF, black is line color
+ lda VERA::DATA0 ; Load the byte at memory address
+ and bitMasks2,X ; OR with the bit mask
+ sta VERA::DATA0 ; Store back the modified byte
+ rts
+
+; ------------------------------------------------------------------------
+; GETPIXEL: Read the color value of a pixel, and return it in .XA. The
+; co-ordinates passed to this function never are outside the visible screen
+; area, so there is no need for clipping inside this function.
+
+GETPIXEL:
+ jsr CALC
+
+ stx TEMP
+
+ lda ADDR
+ ldy ADDR+1
+ ldx #$00
+
+ sta VERA::ADDR
+ sty VERA::ADDR + 1
+ stx VERA::ADDR + 2
+
+ ldx TEMP
+ lda VERA::DATA0 ; Load the byte at memory address
+ and bitMasks1,X
+
+ bne @ahead
+
+ ldx #$00
+ lda #$00
+ rts
+
+@ahead:
+ ldx #$00
+ lda #$01
+ rts
+
+; ------------------------------------------------------------------------
+; BAR: Draw a filled rectangle with the corners X1/Y1, X2/Y2, where
+; X1/Y1 = ptr1/ptr2 and X2/Y2 = ptr3/ptr4, using the current drawing color.
+; Contrary to most other functions, the graphics kernel will sort and clip
+; the co-ordinates before calling the driver; so on entry, the following
+; conditions are valid:
+; X1 <= X2
+; Y1 <= Y2
+; (X1 >= 0) && (X1 < XRES)
+; (X2 >= 0) && (X2 < XRES)
+; (Y1 >= 0) && (Y1 < YRES)
+; (Y2 >= 0) && (Y2 < YRES)
+;
+; Must set an error code: NO
+
+BAR:
+ ; Initialize tempY with Y1
+ lda Y1
+ sta tempY
+ lda Y1+1
+ sta tempY+1
+
+@outer_loop:
+ ; Compare tempY with Y2
+ lda tempY+1
+ cmp Y2+1
+ bcc @outer_continue ; If tempY high byte < Y2 high byte, continue
+ bne @outer_end ; If tempY high byte > Y2 high byte, end
+ lda tempY
+ cmp Y2
+ bcc @outer_continue ; If tempY low byte < Y2 low byte, continue
+ beq @outer_end ; If tempY low byte = Y2 low byte, end
+
+@outer_continue:
+ ; Initialize tempX with X1
+ lda X1
+ sta tempX
+ lda X1+1
+ sta tempX+1
+
+@inner_loop:
+ ; Compare tempX with X2
+ lda tempX+1
+ cmp X2+1
+ bcc @inner_continue ; If tempX high byte < X2 high byte, continue
+ bne @inner_end ; If tempX high byte > X2 high byte, end
+ lda tempX
+ cmp X2
+ bcc @inner_continue ; If tempX low byte < X2 low byte, continue
+
+@inner_end:
+ ; Increment tempY
+ inc tempY
+ bne @outer_loop ; If no overflow, continue outer loop
+ inc tempY+1 ; If overflow, increment high byte
+
+@inner_continue:
+ ; Call setpixel(tempX, tempY)
+ lda X1
+ pha
+ lda X1+1
+ pha
+ lda Y1
+ pha
+ lda Y1+1
+ pha
+
+ lda tempX
+ ldx tempX+1
+ sta X1
+ stx X1+1
+
+ lda tempY
+ ldx tempY+1
+ sta Y1
+ stx Y1+1
+
+ jsr SETPIXEL
+
+ pla
+ sta Y1+1
+ pla
+ sta Y1
+ pla
+ sta X1+1
+ pla
+ sta X1
+
+ ; Increment tempX
+ inc tempX
+ bne @inner_loop_check ; If no overflow, continue
+ inc tempX+1 ; If overflow, increment high byte
+
+@inner_loop_check:
+ ; Compare tempX with X2 again after increment
+ lda tempX+1
+ cmp X2+1
+ bcc @inner_continue ; If tempX high byte < X2 high byte, continue
+ bne @outer_increment ; If tempX high byte > X2 high byte, increment tempY
+ lda tempX
+ cmp X2
+ bcc @inner_continue ; If tempX low byte < X2 low byte, continue
+
+@outer_increment:
+ ; Increment tempY
+ inc tempY
+ bne @outer_loop ; If no overflow, continue outer loop
+ inc tempY+1 ; If overflow, increment high byte
+
+@outer_end:
+ jmp @done
+
+@done:
+ rts
+
+; ------------------------------------------------------------------------
+; TEXTSTYLE: Set the style used when calling OUTTEXT. Text scaling in X and Y
+; directions are passed in .X and .Y, the text direction is passed in .A.
+;
+; Must set an error code: NO
+
+TEXTSTYLE:
+ rts
+
+; ------------------------------------------------------------------------
+; OUTTEXT: Output text at X/Y = ptr1/ptr2 using the current color and the
+; current text style. The text to output is given as a zero-terminated
+; string with address in ptr3.
+;
+; Must set an error code: NO
+
+OUTTEXT:
+ rts
+
+
+; ------------------------------------------------------------------------
+; Calculate all variables to plot the pixel at X1/Y1.
+;------------------------
+;< X1,Y1 - pixel
+;> ADDR - address of card
+;> X - bit number (X1 & 7)
+CALC:
+ lda Y1+1
+ sta ADDR+1
+ lda Y1
+ asl
+ rol ADDR+1
+ asl
+ rol ADDR+1 ; Y*4
+ clc
+ adc Y1
+ sta ADDR
+ lda Y1+1
+ adc ADDR+1
+ sta ADDR+1 ; Y*4+Y=Y*5
+ lda ADDR
+ asl
+ rol ADDR+1
+ asl
+ rol ADDR+1
+ asl
+ rol ADDR+1
+ asl
+ rol ADDR+1
+ sta ADDR ; Y*5*16=Y*80
+ lda X1+1
+ sta TEMP
+ lda X1
+ lsr TEMP
+ ror
+ lsr TEMP
+ ror
+ lsr TEMP
+ ror
+ clc
+ adc ADDR
+ sta ADDR
+ lda ADDR+1 ; ADDR = Y*80+x/8
+ adc TEMP
+ sta ADDR+1
+ lda ADDR+1
+ lda X1
+ and #7
+ tax
+ rts
+
+
+.include "../../tgi/tgidrv_line.inc"
diff --git a/libsrc/pet/waitvsync.s b/libsrc/pet/waitvsync.s
index 39b562e43..d74f76c9f 100644
--- a/libsrc/pet/waitvsync.s
+++ b/libsrc/pet/waitvsync.s
@@ -9,8 +9,7 @@
.include "pet.inc"
_waitvsync:
-@l1:
- lda VIA_PB
- and #%00100000
- bne @l1
+ lda #%00100000
+: and VIA_PB
+ bne :-
rts
diff --git a/libsrc/sim6502/exehdr.s b/libsrc/sim6502/exehdr.s
index 09d099da5..529ad9b94 100644
--- a/libsrc/sim6502/exehdr.s
+++ b/libsrc/sim6502/exehdr.s
@@ -9,11 +9,21 @@
.import __MAIN_START__
.import startup
+ .macpack cpu
+
.segment "EXEHDR"
.byte $73, $69, $6D, $36, $35 ; 'sim65'
.byte 2 ; header version
- .byte .defined(__SIM65C02__) ; CPU type
+.if (.cpu .bitand ::CPU_ISET_6502X)
+ .byte 2
+.elseif (.cpu .bitand ::CPU_ISET_65C02)
+ .byte 1
+.elseif (.cpu .bitand ::CPU_ISET_6502)
+ .byte 0
+.else
+ .error Unknow CPU type.
+.endif
.byte sp ; sp address
.addr __MAIN_START__ ; load address
.addr startup ; reset address
diff --git a/samples/cbm/Makefile b/samples/cbm/Makefile
index 03387a061..4b89722d2 100644
--- a/samples/cbm/Makefile
+++ b/samples/cbm/Makefile
@@ -80,17 +80,19 @@ ifneq ($(filter disk samples.%,$(MAKECMDGOALS)),)
C1541 ?= c1541
endif
-DISK_c64 = samples.d64
+DISK_$(SYS) = samples.d64
EXELIST_c64 = \
fire \
plasma \
- nachtm
+ nachtm \
+ hello
EXELIST_c128 = \
fire \
plasma \
- nachtm
+ nachtm \
+ hello
EXELIST_cbm510 = \
fire \
@@ -101,16 +103,17 @@ EXELIST_cbm610 = \
nachtm
EXELIST_plus4 = \
- plasma
+ plasma \
+ hello
EXELIST_c16 = \
- notavailable
+ hello
EXELIST_pet = \
notavailable
EXELIST_vic20 = \
- notavailable
+ hello
ifneq ($(EXELIST_$(SYS)),)
samples: $(EXELIST_$(SYS))
@@ -135,6 +138,15 @@ plasma: plasma.c
$(CL) -t $(SYS) -O -o plasma -m plasma.map plasma.c
nachtm: nachtm.c
$(CL) -t $(SYS) -O -o nachtm -m nachtm.map nachtm.c
+hello: hello-asm.s
+ # Use separate assembler ...
+ $(AS) -t $(SYS) hello-asm.s
+ # ... and linker commands ...
+ $(LD) -C $(SYS)-asm.cfg -o hello -m hello-asm.map -u __EXEHDR__ hello-asm.o $(SYS).lib
+ @$(DEL) hello-asm.o 2>$(NULLDEV)
+ # ... or compile & link utility
+# $(CL) -C $(SYS)-asm.cfg -o hello -m hello-asm.map -u __EXEHDR__ hello-asm.s
+
# --------------------------------------------------------------------------
# Rule to make a CBM disk with all samples. Needs the c1541 program that comes
diff --git a/samples/cbm/hello-asm.s b/samples/cbm/hello-asm.s
new file mode 100644
index 000000000..689dcc06b
--- /dev/null
+++ b/samples/cbm/hello-asm.s
@@ -0,0 +1,15 @@
+;
+; Sample assembly program for Commodore machines
+;
+
+ .include "cbm_kernal.inc"
+
+ ldx #$00
+: lda text,x
+ beq out
+ jsr CHROUT
+ inx
+ bne :-
+out: rts
+
+text: .asciiz "hello world!"
diff --git a/src/ca65/condasm.c b/src/ca65/condasm.c
index 6198f4017..f872ec9ed 100644
--- a/src/ca65/condasm.c
+++ b/src/ca65/condasm.c
@@ -133,24 +133,26 @@ static void SetIfCond (IfDesc* ID, int C)
-static void ElseClause (IfDesc* ID, const char* Directive)
-/* Enter an .ELSE clause */
+static int ElseClause (IfDesc* ID, const char* Directive)
+/* Enter an .ELSE clause. Return true if this was ok, zero on errors. */
{
/* Check if we have an open .IF - otherwise .ELSE is not allowed */
if (ID == 0) {
Error ("Unexpected %s", Directive);
- return;
+ return 0;
}
/* Check for a duplicate else, then remember that we had one */
if (ID->Flags & ifElse) {
/* We already had a .ELSE ! */
Error ("Duplicate .ELSE");
+ return 0;
}
ID->Flags |= ifElse;
/* Condition is inverted now */
ID->Flags ^= ifCond;
+ return 1;
}
@@ -226,46 +228,52 @@ void DoConditionals (void)
D = GetCurrentIf ();
/* Allow an .ELSE */
- ElseClause (D, ".ELSE");
+ if (ElseClause (D, ".ELSE")) {
+ /* Remember the data for the .ELSE */
+ if (D) {
+ ReleaseFullLineInfo (&D->LineInfos);
+ GetFullLineInfo (&D->LineInfos);
+ D->Name = ".ELSE";
+ }
- /* Remember the data for the .ELSE */
- if (D) {
- ReleaseFullLineInfo (&D->LineInfos);
- GetFullLineInfo (&D->LineInfos);
- D->Name = ".ELSE";
+ /* Calculate the new overall condition */
+ CalcOverallIfCond ();
+
+ /* Skip .ELSE */
+ NextTok ();
+ ExpectSep ();
+ } else {
+ /* Problem with .ELSE, ignore remainder of line */
+ SkipUntilSep ();
}
-
- /* Calculate the new overall condition */
- CalcOverallIfCond ();
-
- /* Skip .ELSE */
- NextTok ();
- ExpectSep ();
break;
case TOK_ELSEIF:
D = GetCurrentIf ();
/* Handle as if there was an .ELSE first */
- ElseClause (D, ".ELSEIF");
+ if (ElseClause (D, ".ELSEIF")) {
+ /* Calculate the new overall if condition */
+ CalcOverallIfCond ();
- /* Calculate the new overall if condition */
- CalcOverallIfCond ();
+ /* Allocate and prepare a new descriptor */
+ D = AllocIf (".ELSEIF", 0);
+ NextTok ();
- /* Allocate and prepare a new descriptor */
- D = AllocIf (".ELSEIF", 0);
- NextTok ();
+ /* Ignore the new condition if we are inside a false .ELSE
+ ** branch. This way we won't get any errors about undefined
+ ** symbols or similar...
+ */
+ if (IfCond) {
+ SetIfCond (D, ConstExpression ());
+ ExpectSep ();
+ }
- /* Ignore the new condition if we are inside a false .ELSE
- ** branch. This way we won't get any errors about undefined
- ** symbols or similar...
- */
- if (IfCond) {
- SetIfCond (D, ConstExpression ());
- ExpectSep ();
+ /* Get the new overall condition */
+ CalcOverallIfCond ();
+ } else {
+ /* Problem with .ELSEIF, ignore remainder of line */
+ SkipUntilSep ();
}
-
- /* Get the new overall condition */
- CalcOverallIfCond ();
break;
case TOK_ENDIF:
diff --git a/src/ca65/istack.c b/src/ca65/istack.c
index 7a95e7e8c..979c09740 100644
--- a/src/ca65/istack.c
+++ b/src/ca65/istack.c
@@ -156,3 +156,29 @@ void CheckInputStack (void)
Error ("Open %s", IStack->Desc);
}
}
+
+
+
+InputStack RetrieveInputStack (void)
+/* Retrieve the current input stack. This will also clear it. Used when
+** including a file. The current input stack is stored together with the old
+** input file and restored when the file is closed.
+ */
+{
+ /* We do not touch the counter so input sources are counted across
+ ** includes.
+ */
+ InputStack S = IStack;
+ IStack = 0;
+ return S;
+}
+
+
+
+void RestoreInputStack (InputStack S)
+/* Restore an old input stack that was retrieved by RetrieveInputStack(). */
+{
+ CHECK (IStack == 0);
+ IStack = S;
+}
+
diff --git a/src/ca65/istack.h b/src/ca65/istack.h
index aa37bab14..28c413d39 100644
--- a/src/ca65/istack.h
+++ b/src/ca65/istack.h
@@ -38,6 +38,17 @@
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Opaque pointer to an input stack */
+typedef void* InputStack;
+
+
+
/*****************************************************************************/
/* Code */
/*****************************************************************************/
@@ -63,6 +74,15 @@ void CheckInputStack (void);
** stuff on the input stack.
*/
+InputStack RetrieveInputStack (void);
+/* Retrieve the current input stack. This will also clear it. Used when
+** including a file. The current input stack is stored together with the old
+** input file and restored when the file is closed.
+ */
+
+void RestoreInputStack (InputStack S);
+/* Restore an old input stack that was retrieved by RetrieveInputStack(). */
+
/* End of istack.h */
diff --git a/src/ca65/main.c b/src/ca65/main.c
index 3ec6c84ee..f3100162a 100644
--- a/src/ca65/main.c
+++ b/src/ca65/main.c
@@ -707,6 +707,24 @@ static void OneLine (void)
NextTok ();
}
+ /* Handle @-style unnamed labels */
+ if (CurTok.Tok == TOK_ULABEL) {
+ if (CurTok.IVal != 0) {
+ Error ("Invalid unnamed label definition");
+ }
+ ULabDef ();
+ NextTok ();
+
+ /* Skip the colon. If NoColonLabels is enabled, allow labels without
+ ** a colon if there is no whitespace before the identifier.
+ */
+ if (CurTok.Tok == TOK_COLON) {
+ NextTok ();
+ } else if (CurTok.WS || !NoColonLabels) {
+ Error ("':' expected");
+ }
+ }
+
/* If the first token on the line is an identifier, check for a macro or
** an instruction.
*/
diff --git a/src/ca65/scanner.c b/src/ca65/scanner.c
index 185100025..89ff851fc 100644
--- a/src/ca65/scanner.c
+++ b/src/ca65/scanner.c
@@ -113,6 +113,7 @@ struct CharSource {
token_t Tok; /* Last token */
int C; /* Last character */
int SkipN; /* For '\r\n' line endings, skip '\n\ if next */
+ InputStack IStack; /* Saved input stack */
const CharSourceFunctions* Func; /* Pointer to function table */
union {
InputFile File; /* File data */
@@ -321,6 +322,9 @@ static void UseCharSource (CharSource* S)
S->Tok = CurTok.Tok;
S->C = C;
+ /* Remember the current input stack */
+ S->IStack = RetrieveInputStack ();
+
/* Use the new input source */
S->Next = Source;
Source = S;
@@ -347,7 +351,10 @@ static void DoneCharSource (void)
/* Restore the old token */
CurTok.Tok = Source->Tok;
- C = Source->C;
+ C = Source->C;
+
+ /* Restore the old input source */
+ RestoreInputStack (Source->IStack);
/* Remember the last stacked input source */
S = Source->Next;
@@ -1124,17 +1131,33 @@ Again:
/* Local symbol? */
if (C == LocalStart) {
- /* Read the identifier. */
- ReadIdent ();
+ NextChar ();
- /* Start character alone is not enough */
- if (SB_GetLen (&CurTok.SVal) == 1) {
- Error ("Invalid cheap local symbol");
- goto Again;
+ if (IsIdChar (C)) {
+ /* Read a local identifier */
+ CurTok.Tok = TOK_LOCAL_IDENT;
+ SB_AppendChar (&CurTok.SVal, LocalStart);
+ ReadIdent ();
+ } else {
+ /* Read an unnamed label */
+ CurTok.IVal = 0;
+ CurTok.Tok = TOK_ULABEL;
+
+ if (C == '-' || C == '<') {
+ int PrevC = C;
+ do {
+ --CurTok.IVal;
+ NextChar ();
+ } while (C == PrevC);
+ } else if (C == '+' || C == '>') {
+ int PrevC = C;
+ do {
+ ++CurTok.IVal;
+ NextChar ();
+ } while (C == PrevC);
+ }
}
- /* A local identifier */
- CurTok.Tok = TOK_LOCAL_IDENT;
return;
}
@@ -1314,22 +1337,30 @@ CharAgain:
break;
case '-':
+ case '<':
+ {
+ int PrevC = C;
CurTok.IVal = 0;
do {
--CurTok.IVal;
NextChar ();
- } while (C == '-');
+ } while (C == PrevC);
CurTok.Tok = TOK_ULABEL;
break;
+ }
case '+':
+ case '>':
+ {
+ int PrevC = C;
CurTok.IVal = 0;
do {
++CurTok.IVal;
NextChar ();
- } while (C == '+');
+ } while (C == PrevC);
CurTok.Tok = TOK_ULABEL;
break;
+ }
case '=':
NextChar ();
@@ -1497,7 +1528,7 @@ CharAgain:
/* In case of the main file, do not close it, but return EOF. */
if (Source && Source->Next) {
DoneCharSource ();
- goto Again;
+ goto Restart;
} else {
CurTok.Tok = TOK_EOF;
}
diff --git a/src/ca65/token.h b/src/ca65/token.h
index b8bbb6d6e..8f935f7a1 100644
--- a/src/ca65/token.h
+++ b/src/ca65/token.h
@@ -71,7 +71,7 @@ typedef enum token_t {
TOK_REG, /* Sweet16 R.. register (in sweet16 mode) */
TOK_ASSIGN, /* := */
- TOK_ULABEL, /* :++ or :-- */
+ TOK_ULABEL, /* An unnamed label */
TOK_EQ, /* = */
TOK_NE, /* <> */
diff --git a/src/ca65/ulabel.c b/src/ca65/ulabel.c
index 1127c3743..19bec0671 100644
--- a/src/ca65/ulabel.c
+++ b/src/ca65/ulabel.c
@@ -107,8 +107,12 @@ ExprNode* ULabRef (int Which)
int Index;
ULabel* L;
- /* Which can never be 0 */
- PRECONDITION (Which != 0);
+ /* Which should not be 0 */
+ if (Which == 0) {
+ Error ("Invalid unnamed label reference");
+ /* We must return something valid */
+ return GenCurrentPC();
+ }
/* Get the index of the referenced label */
if (Which > 0) {
diff --git a/src/cc65/codegen.c b/src/cc65/codegen.c
index 69dcc1c6c..166176f5e 100644
--- a/src/cc65/codegen.c
+++ b/src/cc65/codegen.c
@@ -507,34 +507,39 @@ void g_enter (unsigned flags, unsigned argsize)
-void g_leave (void)
+void g_leave (int DoCleanup)
/* Function epilogue */
{
- /* How many bytes of locals do we have to drop? */
- unsigned ToDrop = (unsigned) -StackPtr;
+ /* In the main function in cc65 mode nothing has to be dropped because
+ ** the program is terminated anyway.
+ */
+ if (DoCleanup) {
+ /* How many bytes of locals do we have to drop? */
+ unsigned ToDrop = (unsigned) -StackPtr;
- /* If we didn't have a variable argument list, don't call leave */
- if (funcargs >= 0) {
+ /* If we didn't have a variable argument list, don't call leave */
+ if (funcargs >= 0) {
- /* Drop stackframe if needed */
- g_drop (ToDrop + funcargs);
+ /* Drop stackframe if needed */
+ g_drop (ToDrop + funcargs);
- } else if (StackPtr != 0) {
+ } else if (StackPtr != 0) {
+
+ /* We've a stack frame to drop */
+ if (ToDrop > 255) {
+ g_drop (ToDrop); /* Inlines the code */
+ AddCodeLine ("jsr leave");
+ } else {
+ AddCodeLine ("ldy #$%02X", ToDrop);
+ AddCodeLine ("jsr leavey");
+ }
- /* We've a stack frame to drop */
- if (ToDrop > 255) {
- g_drop (ToDrop); /* Inlines the code */
- AddCodeLine ("jsr leave");
} else {
- AddCodeLine ("ldy #$%02X", ToDrop);
- AddCodeLine ("jsr leavey");
+
+ /* Nothing to drop */
+ AddCodeLine ("jsr leave");
+
}
-
- } else {
-
- /* Nothing to drop */
- AddCodeLine ("jsr leave");
-
}
/* Add the final rts */
diff --git a/src/cc65/codegen.h b/src/cc65/codegen.h
index 8e04b45e4..734c95372 100644
--- a/src/cc65/codegen.h
+++ b/src/cc65/codegen.h
@@ -247,7 +247,7 @@ void g_scale (unsigned flags, long val);
void g_enter (unsigned flags, unsigned argsize);
/* Function prologue */
-void g_leave (void);
+void g_leave (int DoCleanup);
/* Function epilogue */
diff --git a/src/cc65/codeoptutil.c b/src/cc65/codeoptutil.c
index 173d5185f..43b1dee22 100644
--- a/src/cc65/codeoptutil.c
+++ b/src/cc65/codeoptutil.c
@@ -1128,8 +1128,10 @@ void AddOpHigh (StackOpData* D, opc_t OPC, LoadInfo* LI, int KeepResult)
InsertEntry (D, X, D->IP++);
}
- /* In both cases, we can remove the load */
- LI->X.Flags |= LI_REMOVE;
+ /* If this is the right hand side, we can remove the load. */
+ if (LI == &D->Rhs) {
+ LI->X.Flags |= LI_REMOVE;
+ }
} else {
/* opc zphi */
diff --git a/src/cc65/declare.c b/src/cc65/declare.c
index e1e66ab85..e9f519ebe 100644
--- a/src/cc65/declare.c
+++ b/src/cc65/declare.c
@@ -71,17 +71,33 @@
-static void ParseTypeSpec (DeclSpec* Spec, typespec_t TSFlags);
-/* Parse a type specifier */
+static SymEntry* ParseEnumSpec (const char* Name, unsigned* DSFlags);
+/* Parse an enum specifier */
+
+static SymEntry* ParseUnionSpec (const char* Name, unsigned* DSFlags);
+/* Parse a union specifier */
+
+static SymEntry* ParseStructSpec (const char* Name, unsigned* DSFlags);
+/* Parse a struct specifier */
/*****************************************************************************/
-/* Internal functions */
+/* Type specification parser */
/*****************************************************************************/
+static void InitDeclSpec (DeclSpec* Spec)
+/* Initialize the DeclSpec struct for use */
+{
+ Spec->StorageClass = 0;
+ Spec->Type[0].C = T_END;
+ Spec->Flags = 0;
+}
+
+
+
static unsigned ParseOneStorageClass (void)
/* Parse and return a storage class specifier */
{
@@ -421,255 +437,284 @@ static void UseDefaultType (DeclSpec* Spec, typespec_t TSFlags)
-static void InitDeclSpec (DeclSpec* Spec)
-/* Initialize the DeclSpec struct for use */
-{
- Spec->StorageClass = 0;
- Spec->Type[0].C = T_END;
- Spec->Flags = 0;
-}
-
-
-
-static void InitDeclarator (Declarator* D)
-/* Initialize the Declarator struct for use */
-{
- D->Ident[0] = '\0';
- D->Type[0].C = T_END;
- D->Index = 0;
- D->Attributes = 0;
-}
-
-
-
-static void NeedTypeSpace (Declarator* D, unsigned Count)
-/* Check if there is enough space for Count type specifiers within D */
-{
- if (D->Index + Count >= MAXTYPELEN) {
- /* We must call Fatal() here, since calling Error() will try to
- ** continue, and the declaration type is not correctly terminated
- ** in case we come here.
- */
- Fatal ("Too many type specifiers");
- }
-}
-
-
-
-static void AddTypeCodeToDeclarator (Declarator* D, TypeCode T)
-/* Add a type specifier to the type of a declarator */
-{
- NeedTypeSpace (D, 1);
- D->Type[D->Index++].C = T;
-}
-
-
-
-static void FixQualifiers (Type* DataType)
-/* Apply several fixes to qualifiers */
-{
- Type* T;
- TypeCode Q;
-
- /* Using typedefs, it is possible to generate declarations that have
- ** type qualifiers attached to an array, not the element type. Go and
- ** fix these here.
- */
- T = DataType;
- Q = T_QUAL_NONE;
- while (T->C != T_END) {
- if (IsTypeArray (T)) {
- /* Extract any type qualifiers */
- Q |= GetQualifier (T);
- T->C = GetUnqualRawTypeCode (T);
- } else {
- /* Add extracted type qualifiers here */
- T->C |= Q;
- Q = T_QUAL_NONE;
- }
- ++T;
- }
- /* Q must be empty now */
- CHECK (Q == T_QUAL_NONE);
-
- /* Do some fixes on pointers and functions. */
- T = DataType;
- while (T->C != T_END) {
- if (IsTypePtr (T)) {
- /* Calling convention qualifier on the pointer? */
- if (IsQualCConv (T)) {
- /* Pull the convention off of the pointer */
- Q = T[0].C & T_QUAL_CCONV;
- T[0].C &= ~T_QUAL_CCONV;
-
- /* Pointer to a function which doesn't have an explicit convention? */
- if (IsTypeFunc (T + 1)) {
- if (IsQualCConv (T + 1)) {
- if ((T[1].C & T_QUAL_CCONV) == Q) {
- Warning ("Pointer duplicates function's calling convention");
- } else {
- Error ("Function's and pointer's calling conventions are different");
- }
- } else {
- if (Q == T_QUAL_FASTCALL && IsVariadicFunc (T + 1)) {
- Error ("Variadic-function pointers cannot be __fastcall__");
- } else {
- /* Move the qualifier from the pointer to the function. */
- T[1].C |= Q;
- }
- }
- } else {
- Error ("Not pointer to a function; can't use a calling convention");
- }
- }
-
- /* Apply the default far and near qualifiers if none are given */
- Q = (T[0].C & T_QUAL_ADDRSIZE);
- if (Q == T_QUAL_NONE) {
- /* No address size qualifiers specified */
- if (IsTypeFunc (T+1)) {
- /* Pointer to function. Use the qualifier from the function,
- ** or the default if the function doesn't have one.
- */
- Q = (T[1].C & T_QUAL_ADDRSIZE);
- if (Q == T_QUAL_NONE) {
- Q = CodeAddrSizeQualifier ();
- }
- } else {
- Q = DataAddrSizeQualifier ();
- }
- T[0].C |= Q;
- } else {
- /* We have address size qualifiers. If followed by a function,
- ** apply them to the function also.
- */
- if (IsTypeFunc (T+1)) {
- TypeCode FQ = (T[1].C & T_QUAL_ADDRSIZE);
- if (FQ == T_QUAL_NONE) {
- T[1].C |= Q;
- } else if (FQ != Q) {
- Error ("Address size qualifier mismatch");
- T[1].C = (T[1].C & ~T_QUAL_ADDRSIZE) | Q;
- }
- }
- }
-
- } else if (IsTypeFunc (T)) {
-
- /* Apply the default far and near qualifiers if none are given */
- if ((T[0].C & T_QUAL_ADDRSIZE) == 0) {
- T[0].C |= CodeAddrSizeQualifier ();
- }
-
- } else {
-
- /* If we have remaining qualifiers, flag them as invalid */
- Q = T[0].C;
-
- if (Q & T_QUAL_NEAR) {
- Error ("Invalid '__near__' qualifier");
- Q &= ~T_QUAL_NEAR;
- }
- if (Q & T_QUAL_FAR) {
- Error ("Invalid '__far__' qualifier");
- Q &= ~T_QUAL_FAR;
- }
- if (Q & T_QUAL_FASTCALL) {
- Error ("Invalid '__fastcall__' qualifier");
- Q &= ~T_QUAL_FASTCALL;
- }
- if (Q & T_QUAL_CDECL) {
- Error ("Invalid '__cdecl__' qualifier");
- Q &= ~T_QUAL_CDECL;
- }
-
- /* Clear the invalid qualifiers */
- T[0].C &= Q;
-
- }
- ++T;
- }
-}
-
-
-
-static void FixFunctionReturnType (Type* T)
-/* Check if the data type consists of any functions returning forbidden return
-** types and remove qualifiers from the return types if they are not void.
+static void ParseTypeSpec (DeclSpec* Spec, typespec_t TSFlags)
+/* Parse a type specifier. Store whether one of "signed" or "unsigned" was
+** specified, so bit-fields of unspecified signedness can be treated as
+** unsigned; without special handling, it would be treated as signed.
*/
{
- while (T->C != T_END) {
- if (IsTypeFunc (T)) {
- ++T;
+ ident Ident;
+ SymEntry* TagEntry;
+ TypeCode Qualifiers = T_QUAL_NONE;
- /* Functions may not return functions or arrays */
- if (IsTypeFunc (T)) {
- Error ("Functions are not allowed to return functions");
- } else if (IsTypeArray (T)) {
- Error ("Functions are not allowed to return arrays");
+ /* Assume we have an explicitly specified type */
+ Spec->Flags = (Spec->Flags & ~DS_TYPE_MASK) | DS_EXPLICIT_TYPE;
+
+ /* Read storage specifiers and/or type qualifiers if we have any */
+ OptionalSpecifiers (Spec, &Qualifiers, TSFlags);
+
+ /* Look at the data type */
+ switch (CurTok.Tok) {
+
+ case TOK_VOID:
+ NextToken ();
+ Spec->Type[0].C = T_VOID;
+ Spec->Type[0].A.U = 0;
+ Spec->Type[1].C = T_END;
+ break;
+
+ case TOK_CHAR:
+ NextToken ();
+ Spec->Type[0].C = T_CHAR;
+ Spec->Type[1].C = T_END;
+ break;
+
+ case TOK_LONG:
+ NextToken ();
+ if (CurTok.Tok == TOK_UNSIGNED) {
+ Spec->Flags |= DS_EXPLICIT_SIGNEDNESS;
+ NextToken ();
+ OptionalInt ();
+ Spec->Type[0].C = T_ULONG;
+ Spec->Type[1].C = T_END;
+ } else {
+ OptionalSigned (Spec);
+ OptionalInt ();
+ Spec->Type[0].C = T_LONG;
+ Spec->Type[1].C = T_END;
}
+ break;
- /* The return type must not be qualified */
- if ((GetQualifier (T) & T_QUAL_CVR) != T_QUAL_NONE) {
- /* We are stricter than the standard here */
- if (GetRawTypeRank (T) == T_RANK_VOID) {
- /* A qualified void type is always an error */
- Error ("Function definition has qualified void return type");
- } else {
- /* For others, qualifiers are ignored */
- Warning ("Type qualifiers ignored on function return type");
- T[0].C &= ~T_QUAL_CVR;
- }
+ case TOK_SHORT:
+ NextToken ();
+ if (CurTok.Tok == TOK_UNSIGNED) {
+ Spec->Flags |= DS_EXPLICIT_SIGNEDNESS;
+ NextToken ();
+ OptionalInt ();
+ Spec->Type[0].C = T_USHORT;
+ Spec->Type[1].C = T_END;
+ } else {
+ OptionalSigned (Spec);
+ OptionalInt ();
+ Spec->Type[0].C = T_SHORT;
+ Spec->Type[1].C = T_END;
}
- } else {
- ++T;
- }
- }
-}
+ break;
+ case TOK_INT:
+ NextToken ();
+ Spec->Type[0].C = T_INT;
+ Spec->Type[1].C = T_END;
+ break;
+ case TOK_SIGNED:
+ Spec->Flags |= DS_EXPLICIT_SIGNEDNESS;
+ NextToken ();
+ switch (CurTok.Tok) {
-static void CheckArrayElementType (const Type* T)
-/* Check recursively if type consists of arrays of forbidden element types */
-{
- while (T->C != T_END) {
- if (IsTypeArray (T)) {
- /* If the array is multi-dimensional, keep going until we get the
- ** true element type.
+ case TOK_CHAR:
+ NextToken ();
+ Spec->Type[0].C = T_SCHAR;
+ Spec->Type[1].C = T_END;
+ break;
+
+ case TOK_SHORT:
+ NextToken ();
+ OptionalInt ();
+ Spec->Type[0].C = T_SHORT;
+ Spec->Type[1].C = T_END;
+ break;
+
+ case TOK_LONG:
+ NextToken ();
+ OptionalInt ();
+ Spec->Type[0].C = T_LONG;
+ Spec->Type[1].C = T_END;
+ break;
+
+ case TOK_INT:
+ NextToken ();
+ /* FALL THROUGH */
+
+ default:
+ Spec->Type[0].C = T_INT;
+ Spec->Type[1].C = T_END;
+ break;
+ }
+ break;
+
+ case TOK_UNSIGNED:
+ Spec->Flags |= DS_EXPLICIT_SIGNEDNESS;
+ NextToken ();
+ switch (CurTok.Tok) {
+
+ case TOK_CHAR:
+ NextToken ();
+ Spec->Type[0].C = T_UCHAR;
+ Spec->Type[1].C = T_END;
+ break;
+
+ case TOK_SHORT:
+ NextToken ();
+ OptionalInt ();
+ Spec->Type[0].C = T_USHORT;
+ Spec->Type[1].C = T_END;
+ break;
+
+ case TOK_LONG:
+ NextToken ();
+ OptionalInt ();
+ Spec->Type[0].C = T_ULONG;
+ Spec->Type[1].C = T_END;
+ break;
+
+ case TOK_INT:
+ NextToken ();
+ /* FALL THROUGH */
+
+ default:
+ Spec->Type[0].C = T_UINT;
+ Spec->Type[1].C = T_END;
+ break;
+ }
+ break;
+
+ case TOK_FLOAT:
+ NextToken ();
+ Spec->Type[0].C = T_FLOAT;
+ Spec->Type[1].C = T_END;
+ break;
+
+ case TOK_DOUBLE:
+ NextToken ();
+ Spec->Type[0].C = T_DOUBLE;
+ Spec->Type[1].C = T_END;
+ break;
+
+ case TOK_UNION:
+ NextToken ();
+ /* Remember we have an extra type decl */
+ Spec->Flags |= DS_EXTRA_TYPE;
+ /* Check for tag name */
+ if (CurTok.Tok == TOK_IDENT) {
+ strcpy (Ident, CurTok.Ident);
+ NextToken ();
+ } else if (CurTok.Tok == TOK_LCURLY) {
+ AnonName (Ident, "union");
+ } else {
+ Error ("Tag name identifier or '{' expected");
+ UseDefaultType (Spec, TS_DEFAULT_TYPE_NONE);
+ break;
+ }
+ /* Declare the union in the current scope */
+ TagEntry = ParseUnionSpec (Ident, &Spec->Flags);
+ /* Encode the union entry into the type */
+ Spec->Type[0].C = T_UNION;
+ SetESUTagSym (Spec->Type, TagEntry);
+ Spec->Type[1].C = T_END;
+ break;
+
+ case TOK_STRUCT:
+ NextToken ();
+ /* Remember we have an extra type decl */
+ Spec->Flags |= DS_EXTRA_TYPE;
+ /* Check for tag name */
+ if (CurTok.Tok == TOK_IDENT) {
+ strcpy (Ident, CurTok.Ident);
+ NextToken ();
+ } else if (CurTok.Tok == TOK_LCURLY) {
+ AnonName (Ident, "struct");
+ } else {
+ Error ("Tag name identifier or '{' expected");
+ UseDefaultType (Spec, TS_DEFAULT_TYPE_NONE);
+ break;
+ }
+ /* Declare the struct in the current scope */
+ TagEntry = ParseStructSpec (Ident, &Spec->Flags);
+ /* Encode the struct entry into the type */
+ Spec->Type[0].C = T_STRUCT;
+ SetESUTagSym (Spec->Type, TagEntry);
+ Spec->Type[1].C = T_END;
+ break;
+
+ case TOK_ENUM:
+ NextToken ();
+ /* Remember we have an extra type decl */
+ Spec->Flags |= DS_EXTRA_TYPE;
+ /* Check for tag name */
+ if (CurTok.Tok == TOK_IDENT) {
+ strcpy (Ident, CurTok.Ident);
+ NextToken ();
+ } else if (CurTok.Tok == TOK_LCURLY) {
+ AnonName (Ident, "enum");
+ } else {
+ Error ("Tag name identifier or '{' expected");
+ UseDefaultType (Spec, TS_DEFAULT_TYPE_NONE);
+ break;
+ }
+ /* Parse the enum decl */
+ TagEntry = ParseEnumSpec (Ident, &Spec->Flags);
+ /* Encode the enum entry into the type */
+ Spec->Type[0].C |= T_ENUM;
+ SetESUTagSym (Spec->Type, TagEntry);
+ Spec->Type[1].C = T_END;
+ /* The signedness of enums is determined by the type, so say this is specified to avoid
+ ** the int -> unsigned int handling for plain int bit-fields in AddBitField.
*/
- ++T;
- if (SizeOf (T) == 0) {
- if (IsTypeArray (T) || IsIncompleteESUType (T)) {
- /* We cannot have an array of incomplete elements */
- if (!IsTypeArray (T) || GetElementCount (T) == UNSPECIFIED) {
- Error ("Array of incomplete element type '%s'",
- GetFullTypeName (T));
- return;
- }
- } else if (!IsTypeVoid (T) || IS_Get (&Standard) != STD_CC65) {
- /* We could support certain 0-size element types as an extension */
- Error ("Array of 0-size element type '%s'",
- GetFullTypeName (T));
- return;
+ Spec->Flags |= DS_EXPLICIT_SIGNEDNESS;
+ break;
+
+ case TOK_IDENT:
+ /* This could be a label */
+ if (NextTok.Tok != TOK_COLON || GetLexicalLevel () == LEX_LEVEL_STRUCT) {
+ TagEntry = FindSym (CurTok.Ident);
+ if (TagEntry && SymIsTypeDef (TagEntry)) {
+ /* It's a typedef */
+ NextToken ();
+ TypeCopy (Spec->Type, TagEntry->Type);
+ /* If it's a typedef, we should actually use whether the signedness was
+ ** specified on the typedef, but that information has been lost. Treat the
+ ** signedness as being specified to work around the ICE in #1267.
+ ** Unforunately, this will cause plain int bit-fields defined via typedefs
+ ** to be treated as signed rather than unsigned.
+ */
+ Spec->Flags |= DS_EXPLICIT_SIGNEDNESS;
+ break;
+ } else if ((TSFlags & TS_MASK_DEFAULT_TYPE) == TS_DEFAULT_TYPE_NONE) {
+ /* Treat this identifier as an unknown type */
+ Error ("Unknown type name '%s'", CurTok.Ident);
+ TypeCopy (Spec->Type, type_int);
+ NextToken ();
+ break;
}
} else {
- /* Elements cannot contain flexible array members themselves */
- if (IsClassStruct (T)) {
- SymEntry* TagEntry = GetESUTagSym (T);
- if (TagEntry && SymHasFlexibleArrayMember (TagEntry)) {
- Error ("Invalid use of struct with flexible array member");
- return;
- }
- }
+ /* This is a label. Use the default type flag to end the loop
+ ** in DeclareLocals. The type code used here doesn't matter as
+ ** long as it has no qualifiers.
+ */
+ UseDefaultType (Spec, TS_DEFAULT_TYPE_INT);
+ break;
}
- } else {
- ++T;
- }
+ /* FALL THROUGH */
+
+ default:
+ UseDefaultType (Spec, TSFlags);
+ break;
}
+
+ /* There may also be specifiers/qualifiers *after* the initial type */
+ OptionalSpecifiers (Spec, &Qualifiers, TSFlags);
+ Spec->Type[0].C |= Qualifiers;
}
+/*****************************************************************************/
+/* Enum/struct/union parser */
+/*****************************************************************************/
+
+
+
static SymEntry* ForwardESU (const char* Name, unsigned Flags, unsigned* DSFlags)
/* Handle an enum, struct or union forward declaration */
{
@@ -731,7 +776,7 @@ static const Type* GetEnumeratorType (long Min, unsigned long Max, int Signed)
static SymEntry* ParseEnumSpec (const char* Name, unsigned* DSFlags)
-/* Process an enum specifier */
+/* Parse an enum specifier */
{
SymTable* FieldTab;
long EnumVal;
@@ -905,6 +950,8 @@ static int ParseFieldWidth (Declarator* D)
** otherwise the width of the field.
*/
{
+ ExprDesc Expr;
+
if (CurTok.Tok != TOK_COLON) {
/* No bit-field declaration */
return -1;
@@ -918,7 +965,16 @@ static int ParseFieldWidth (Declarator* D)
/* Avoid a diagnostic storm by giving the bit-field the widest valid
** signed type, and continuing to parse.
*/
- D->Type[0].C = T_INT;
+ D->Type[0].C = T_LONG;
+ }
+
+ if (IsTypeEnum (D->Type) && IsIncompleteESUType (D->Type)) {
+ /* If the type is an enum, it must be complete */
+ Error ("Bit-field has incomplete type '%s'",
+ GetFullTypeName (D->Type));
+
+ /* Avoid a diagnostic storm */
+ D->Type[0].C = T_LONG;
}
/* We currently support integral types up to long */
@@ -927,12 +983,12 @@ static int ParseFieldWidth (Declarator* D)
Error ("cc65 currently supports only long-sized and smaller bit-field types");
/* Avoid a diagnostic storm */
- D->Type[0].C = T_INT;
+ D->Type[0].C = T_LONG;
}
/* Read the width */
NextToken ();
- ExprDesc Expr = NoCodeConstAbsIntExpr (hie1);
+ Expr = NoCodeConstAbsIntExpr (hie1);
if (Expr.IVal < 0) {
Error ("Negative width in bit-field");
@@ -1505,301 +1561,247 @@ EndOfDecl:
-static void ParseTypeSpec (DeclSpec* Spec, typespec_t TSFlags)
-/* Parse a type specifier. Store whether one of "signed" or "unsigned" was
-** specified, so bit-fields of unspecified signedness can be treated as
-** unsigned; without special handling, it would be treated as signed.
-*/
+/*****************************************************************************/
+/* Declarator parser */
+/*****************************************************************************/
+
+
+
+static void InitDeclarator (Declarator* D)
+/* Initialize the Declarator struct for use */
{
- ident Ident;
- SymEntry* TagEntry;
- TypeCode Qualifiers = T_QUAL_NONE;
-
- /* Assume we have an explicitly specified type */
- Spec->Flags = (Spec->Flags & ~DS_TYPE_MASK) | DS_EXPLICIT_TYPE;
-
- /* Read storage specifiers and/or type qualifiers if we have any */
- OptionalSpecifiers (Spec, &Qualifiers, TSFlags);
-
- /* Look at the data type */
- switch (CurTok.Tok) {
-
- case TOK_VOID:
- NextToken ();
- Spec->Type[0].C = T_VOID;
- Spec->Type[0].A.U = 0;
- Spec->Type[1].C = T_END;
- break;
-
- case TOK_CHAR:
- NextToken ();
- Spec->Type[0].C = T_CHAR;
- Spec->Type[1].C = T_END;
- break;
-
- case TOK_LONG:
- NextToken ();
- if (CurTok.Tok == TOK_UNSIGNED) {
- Spec->Flags |= DS_EXPLICIT_SIGNEDNESS;
- NextToken ();
- OptionalInt ();
- Spec->Type[0].C = T_ULONG;
- Spec->Type[1].C = T_END;
- } else {
- OptionalSigned (Spec);
- OptionalInt ();
- Spec->Type[0].C = T_LONG;
- Spec->Type[1].C = T_END;
- }
- break;
-
- case TOK_SHORT:
- NextToken ();
- if (CurTok.Tok == TOK_UNSIGNED) {
- Spec->Flags |= DS_EXPLICIT_SIGNEDNESS;
- NextToken ();
- OptionalInt ();
- Spec->Type[0].C = T_USHORT;
- Spec->Type[1].C = T_END;
- } else {
- OptionalSigned (Spec);
- OptionalInt ();
- Spec->Type[0].C = T_SHORT;
- Spec->Type[1].C = T_END;
- }
- break;
-
- case TOK_INT:
- NextToken ();
- Spec->Type[0].C = T_INT;
- Spec->Type[1].C = T_END;
- break;
-
- case TOK_SIGNED:
- Spec->Flags |= DS_EXPLICIT_SIGNEDNESS;
- NextToken ();
- switch (CurTok.Tok) {
-
- case TOK_CHAR:
- NextToken ();
- Spec->Type[0].C = T_SCHAR;
- Spec->Type[1].C = T_END;
- break;
-
- case TOK_SHORT:
- NextToken ();
- OptionalInt ();
- Spec->Type[0].C = T_SHORT;
- Spec->Type[1].C = T_END;
- break;
-
- case TOK_LONG:
- NextToken ();
- OptionalInt ();
- Spec->Type[0].C = T_LONG;
- Spec->Type[1].C = T_END;
- break;
-
- case TOK_INT:
- NextToken ();
- /* FALL THROUGH */
-
- default:
- Spec->Type[0].C = T_INT;
- Spec->Type[1].C = T_END;
- break;
- }
- break;
-
- case TOK_UNSIGNED:
- Spec->Flags |= DS_EXPLICIT_SIGNEDNESS;
- NextToken ();
- switch (CurTok.Tok) {
-
- case TOK_CHAR:
- NextToken ();
- Spec->Type[0].C = T_UCHAR;
- Spec->Type[1].C = T_END;
- break;
-
- case TOK_SHORT:
- NextToken ();
- OptionalInt ();
- Spec->Type[0].C = T_USHORT;
- Spec->Type[1].C = T_END;
- break;
-
- case TOK_LONG:
- NextToken ();
- OptionalInt ();
- Spec->Type[0].C = T_ULONG;
- Spec->Type[1].C = T_END;
- break;
-
- case TOK_INT:
- NextToken ();
- /* FALL THROUGH */
-
- default:
- Spec->Type[0].C = T_UINT;
- Spec->Type[1].C = T_END;
- break;
- }
- break;
-
- case TOK_FLOAT:
- NextToken ();
- Spec->Type[0].C = T_FLOAT;
- Spec->Type[1].C = T_END;
- break;
-
- case TOK_DOUBLE:
- NextToken ();
- Spec->Type[0].C = T_DOUBLE;
- Spec->Type[1].C = T_END;
- break;
-
- case TOK_UNION:
- NextToken ();
- /* Remember we have an extra type decl */
- Spec->Flags |= DS_EXTRA_TYPE;
- /* Check for tag name */
- if (CurTok.Tok == TOK_IDENT) {
- strcpy (Ident, CurTok.Ident);
- NextToken ();
- } else if (CurTok.Tok == TOK_LCURLY) {
- AnonName (Ident, "union");
- } else {
- Error ("Tag name identifier or '{' expected");
- UseDefaultType (Spec, TS_DEFAULT_TYPE_NONE);
- break;
- }
- /* Declare the union in the current scope */
- TagEntry = ParseUnionSpec (Ident, &Spec->Flags);
- /* Encode the union entry into the type */
- Spec->Type[0].C = T_UNION;
- SetESUTagSym (Spec->Type, TagEntry);
- Spec->Type[1].C = T_END;
- break;
-
- case TOK_STRUCT:
- NextToken ();
- /* Remember we have an extra type decl */
- Spec->Flags |= DS_EXTRA_TYPE;
- /* Check for tag name */
- if (CurTok.Tok == TOK_IDENT) {
- strcpy (Ident, CurTok.Ident);
- NextToken ();
- } else if (CurTok.Tok == TOK_LCURLY) {
- AnonName (Ident, "struct");
- } else {
- Error ("Tag name identifier or '{' expected");
- UseDefaultType (Spec, TS_DEFAULT_TYPE_NONE);
- break;
- }
- /* Declare the struct in the current scope */
- TagEntry = ParseStructSpec (Ident, &Spec->Flags);
- /* Encode the struct entry into the type */
- Spec->Type[0].C = T_STRUCT;
- SetESUTagSym (Spec->Type, TagEntry);
- Spec->Type[1].C = T_END;
- break;
-
- case TOK_ENUM:
- NextToken ();
- /* Remember we have an extra type decl */
- Spec->Flags |= DS_EXTRA_TYPE;
- /* Check for tag name */
- if (CurTok.Tok == TOK_IDENT) {
- strcpy (Ident, CurTok.Ident);
- NextToken ();
- } else if (CurTok.Tok == TOK_LCURLY) {
- AnonName (Ident, "enum");
- } else {
- Error ("Tag name identifier or '{' expected");
- UseDefaultType (Spec, TS_DEFAULT_TYPE_NONE);
- break;
- }
- /* Parse the enum decl */
- TagEntry = ParseEnumSpec (Ident, &Spec->Flags);
- /* Encode the enum entry into the type */
- Spec->Type[0].C |= T_ENUM;
- SetESUTagSym (Spec->Type, TagEntry);
- Spec->Type[1].C = T_END;
- /* The signedness of enums is determined by the type, so say this is specified to avoid
- ** the int -> unsigned int handling for plain int bit-fields in AddBitField.
- */
- Spec->Flags |= DS_EXPLICIT_SIGNEDNESS;
- break;
-
- case TOK_IDENT:
- /* This could be a label */
- if (NextTok.Tok != TOK_COLON || GetLexicalLevel () == LEX_LEVEL_STRUCT) {
- TagEntry = FindSym (CurTok.Ident);
- if (TagEntry && SymIsTypeDef (TagEntry)) {
- /* It's a typedef */
- NextToken ();
- TypeCopy (Spec->Type, TagEntry->Type);
- /* If it's a typedef, we should actually use whether the signedness was
- ** specified on the typedef, but that information has been lost. Treat the
- ** signedness as being specified to work around the ICE in #1267.
- ** Unforunately, this will cause plain int bit-fields defined via typedefs
- ** to be treated as signed rather than unsigned.
- */
- Spec->Flags |= DS_EXPLICIT_SIGNEDNESS;
- break;
- } else if ((TSFlags & TS_MASK_DEFAULT_TYPE) == TS_DEFAULT_TYPE_NONE) {
- /* Treat this identifier as an unknown type */
- Error ("Unknown type name '%s'", CurTok.Ident);
- TypeCopy (Spec->Type, type_int);
- NextToken ();
- break;
- }
- } else {
- /* This is a label. Use the default type flag to end the loop
- ** in DeclareLocals. The type code used here doesn't matter as
- ** long as it has no qualifiers.
- */
- UseDefaultType (Spec, TS_DEFAULT_TYPE_INT);
- break;
- }
- /* FALL THROUGH */
-
- default:
- UseDefaultType (Spec, TSFlags);
- break;
- }
-
- /* There may also be specifiers/qualifiers *after* the initial type */
- OptionalSpecifiers (Spec, &Qualifiers, TSFlags);
- Spec->Type[0].C |= Qualifiers;
+ D->Ident[0] = '\0';
+ D->Type[0].C = T_END;
+ D->Index = 0;
+ D->Attributes = 0;
}
-static const Type* ParamTypeCvt (Type* T)
-/* If T is an array or a function, convert it to a pointer else do nothing.
-** Return the resulting type.
+static void NeedTypeSpace (Declarator* D, unsigned Count)
+/* Check if there is enough space for Count type specifiers within D */
+{
+ if (D->Index + Count >= MAXTYPELEN) {
+ /* We must call Fatal() here, since calling Error() will try to
+ ** continue, and the declaration type is not correctly terminated
+ ** in case we come here.
+ */
+ Fatal ("Too many type specifiers");
+ }
+}
+
+
+
+static void AddTypeCodeToDeclarator (Declarator* D, TypeCode T)
+/* Add a type specifier to the type of a declarator */
+{
+ NeedTypeSpace (D, 1);
+ D->Type[D->Index++].C = T;
+}
+
+
+
+static void FixQualifiers (Type* DataType)
+/* Apply several fixes to qualifiers */
+{
+ Type* T;
+ TypeCode Q;
+
+ /* Using typedefs, it is possible to generate declarations that have
+ ** type qualifiers attached to an array, not the element type. Go and
+ ** fix these here.
+ */
+ T = DataType;
+ Q = T_QUAL_NONE;
+ while (T->C != T_END) {
+ if (IsTypeArray (T)) {
+ /* Extract any type qualifiers */
+ Q |= GetQualifier (T);
+ T->C = GetUnqualRawTypeCode (T);
+ } else {
+ /* Add extracted type qualifiers here */
+ T->C |= Q;
+ Q = T_QUAL_NONE;
+ }
+ ++T;
+ }
+ /* Q must be empty now */
+ CHECK (Q == T_QUAL_NONE);
+
+ /* Do some fixes on pointers and functions. */
+ T = DataType;
+ while (T->C != T_END) {
+ if (IsTypePtr (T)) {
+ /* Calling convention qualifier on the pointer? */
+ if (IsQualCConv (T)) {
+ /* Pull the convention off of the pointer */
+ Q = T[0].C & T_QUAL_CCONV;
+ T[0].C &= ~T_QUAL_CCONV;
+
+ /* Pointer to a function which doesn't have an explicit convention? */
+ if (IsTypeFunc (T + 1)) {
+ if (IsQualCConv (T + 1)) {
+ if ((T[1].C & T_QUAL_CCONV) == Q) {
+ Warning ("Pointer duplicates function's calling convention");
+ } else {
+ Error ("Function's and pointer's calling conventions are different");
+ }
+ } else {
+ if (Q == T_QUAL_FASTCALL && IsVariadicFunc (T + 1)) {
+ Error ("Variadic-function pointers cannot be __fastcall__");
+ } else {
+ /* Move the qualifier from the pointer to the function. */
+ T[1].C |= Q;
+ }
+ }
+ } else {
+ Error ("Not pointer to a function; can't use a calling convention");
+ }
+ }
+
+ /* Apply the default far and near qualifiers if none are given */
+ Q = (T[0].C & T_QUAL_ADDRSIZE);
+ if (Q == T_QUAL_NONE) {
+ /* No address size qualifiers specified */
+ if (IsTypeFunc (T+1)) {
+ /* Pointer to function. Use the qualifier from the function,
+ ** or the default if the function doesn't have one.
+ */
+ Q = (T[1].C & T_QUAL_ADDRSIZE);
+ if (Q == T_QUAL_NONE) {
+ Q = CodeAddrSizeQualifier ();
+ }
+ } else {
+ Q = DataAddrSizeQualifier ();
+ }
+ T[0].C |= Q;
+ } else {
+ /* We have address size qualifiers. If followed by a function,
+ ** apply them to the function also.
+ */
+ if (IsTypeFunc (T+1)) {
+ TypeCode FQ = (T[1].C & T_QUAL_ADDRSIZE);
+ if (FQ == T_QUAL_NONE) {
+ T[1].C |= Q;
+ } else if (FQ != Q) {
+ Error ("Address size qualifier mismatch");
+ T[1].C = (T[1].C & ~T_QUAL_ADDRSIZE) | Q;
+ }
+ }
+ }
+
+ } else if (IsTypeFunc (T)) {
+
+ /* Apply the default far and near qualifiers if none are given */
+ if ((T[0].C & T_QUAL_ADDRSIZE) == 0) {
+ T[0].C |= CodeAddrSizeQualifier ();
+ }
+
+ } else {
+
+ /* If we have remaining qualifiers, flag them as invalid */
+ Q = T[0].C;
+
+ if (Q & T_QUAL_NEAR) {
+ Error ("Invalid '__near__' qualifier");
+ Q &= ~T_QUAL_NEAR;
+ }
+ if (Q & T_QUAL_FAR) {
+ Error ("Invalid '__far__' qualifier");
+ Q &= ~T_QUAL_FAR;
+ }
+ if (Q & T_QUAL_FASTCALL) {
+ Error ("Invalid '__fastcall__' qualifier");
+ Q &= ~T_QUAL_FASTCALL;
+ }
+ if (Q & T_QUAL_CDECL) {
+ Error ("Invalid '__cdecl__' qualifier");
+ Q &= ~T_QUAL_CDECL;
+ }
+
+ /* Clear the invalid qualifiers */
+ T[0].C &= Q;
+
+ }
+ ++T;
+ }
+}
+
+
+
+static void FixFunctionReturnType (Type* T)
+/* Check if the data type consists of any functions returning forbidden return
+** types and remove qualifiers from the return types if they are not void.
*/
{
- Type* Tmp = 0;
+ while (T->C != T_END) {
+ if (IsTypeFunc (T)) {
+ ++T;
- if (IsTypeArray (T)) {
- Tmp = ArrayToPtr (T);
- } else if (IsTypeFunc (T)) {
- Tmp = NewPointerTo (T);
+ /* Functions may not return functions or arrays */
+ if (IsTypeFunc (T)) {
+ Error ("Functions are not allowed to return functions");
+ } else if (IsTypeArray (T)) {
+ Error ("Functions are not allowed to return arrays");
+ }
+
+ /* The return type must not be qualified */
+ if ((GetQualifier (T) & T_QUAL_CVR) != T_QUAL_NONE) {
+ /* We are stricter than the standard here */
+ if (GetRawTypeRank (T) == T_RANK_VOID) {
+ /* A qualified void type is always an error */
+ Error ("Function definition has qualified void return type");
+ } else {
+ /* For others, qualifiers are ignored */
+ Warning ("Type qualifiers ignored on function return type");
+ T[0].C &= ~T_QUAL_CVR;
+ }
+ }
+ } else {
+ ++T;
+ }
}
+}
- if (Tmp != 0) {
- /* Do several fixes on qualifiers */
- FixQualifiers (Tmp);
- /* Replace the type */
- TypeCopy (T, Tmp);
- TypeFree (Tmp);
+
+static void CheckArrayElementType (const Type* T)
+/* Check recursively if type consists of arrays of forbidden element types */
+{
+ while (T->C != T_END) {
+ if (IsTypeArray (T)) {
+ /* If the array is multi-dimensional, keep going until we get the
+ ** true element type.
+ */
+ ++T;
+ if (SizeOf (T) == 0) {
+ if (IsTypeArray (T) || IsIncompleteESUType (T)) {
+ /* We cannot have an array of incomplete elements */
+ if (!IsTypeArray (T) || GetElementCount (T) == UNSPECIFIED) {
+ Error ("Array of incomplete element type '%s'",
+ GetFullTypeName (T));
+ return;
+ }
+ } else if (!IsTypeVoid (T) || IS_Get (&Standard) != STD_CC65) {
+ /* We could support certain 0-size element types as an extension */
+ Error ("Array of 0-size element type '%s'",
+ GetFullTypeName (T));
+ return;
+ }
+ } else {
+ /* Elements cannot contain flexible array members themselves */
+ if (IsClassStruct (T)) {
+ SymEntry* TagEntry = GetESUTagSym (T);
+ if (TagEntry && SymHasFlexibleArrayMember (TagEntry)) {
+ Error ("Invalid use of struct with flexible array member");
+ return;
+ }
+ }
+ }
+ } else {
+ ++T;
+ }
}
-
- return T;
}
@@ -1911,7 +1913,7 @@ static void ParseOldStyleParamDeclList (FuncDesc* F attribute ((unused)))
*/
if (Param->Flags & SC_DEFTYPE) {
/* Found it, change the default type to the one given */
- SymChangeType (Param, ParamTypeCvt (Decl.Type));
+ SymChangeType (Param, PtrConversion (Decl.Type));
/* Reset the "default type" flag */
Param->Flags &= ~SC_DEFTYPE;
} else {
@@ -2024,7 +2026,7 @@ static void ParseAnsiParamList (FuncDesc* F)
ParseAttribute (&Decl);
/* Create a symbol table entry */
- Param = AddLocalSym (Decl.Ident, ParamTypeCvt (Decl.Type), Decl.StorageClass, 0);
+ Param = AddLocalSym (Decl.Ident, PtrConversion (Decl.Type), Decl.StorageClass, 0);
/* Add attributes if we have any */
SymUseAttr (Param, &Decl);
diff --git a/src/cc65/expr.c b/src/cc65/expr.c
index a855e5b3c..2939ab1cc 100644
--- a/src/cc65/expr.c
+++ b/src/cc65/expr.c
@@ -1219,9 +1219,6 @@ static void Primary (ExprDesc* E)
/* Is the symbol known? */
if (Sym) {
- /* We found the symbol - skip the name token */
- NextToken ();
-
/* Check for illegal symbol types */
CHECK ((Sym->Flags & SC_TYPEMASK) != SC_LABEL);
if ((Sym->Flags & SC_TYPEMASK) == SC_TYPEDEF) {
@@ -1230,9 +1227,14 @@ static void Primary (ExprDesc* E)
/* Assume an int type to make E valid */
E->Flags = E_LOC_STACK | E_RTYPE_LVAL;
E->Type = type_int;
+ /* Skip the erroneous token */
+ NextToken ();
break;
}
+ /* Skip the name token */
+ NextToken ();
+
/* Mark the symbol as referenced */
Sym->Flags |= SC_REF;
@@ -1286,7 +1288,23 @@ static void Primary (ExprDesc* E)
** rvalue, too, because we cannot store anything in a function.
** So fix the flags depending on the type.
*/
- if (IsTypeArray (E->Type) || IsTypeFunc (E->Type)) {
+ if (IsTypeArray (E->Type)) {
+ ED_AddrExpr (E);
+ } else if (IsTypeFunc (E->Type)) {
+ /* In cc65 mode we cannot call or take the address of
+ ** main().
+ */
+ if (IS_Get (&Standard) == STD_CC65 &&
+ strcmp (Sym->Name, "main") == 0) {
+ /* Adjust the error message depending on a call or an
+ ** address operation.
+ */
+ if (CurTok.Tok == TOK_LPAREN) {
+ Error ("'main' must not be called recursively");
+ } else {
+ Error ("The address of 'main' cannot be taken");
+ }
+ }
ED_AddrExpr (E);
}
@@ -3272,7 +3290,7 @@ static void parsesub (ExprDesc* Expr)
/* The right hand side is constant. Check left hand side. */
if (ED_IsQuasiConst (Expr)) {
/* We can't do all 'ptr1 - ptr2' constantly at the moment */
- if (Expr->Sym == Expr2.Sym) {
+ if (ED_GetLoc (Expr) == ED_GetLoc (&Expr2) && Expr->Sym == Expr2.Sym) {
Expr->IVal = (Expr->IVal - Expr2.IVal) / rscale;
/* Get rid of unneeded flags etc. */
ED_MakeConstAbsInt (Expr, Expr->IVal);
diff --git a/src/cc65/function.c b/src/cc65/function.c
index a4b860251..fed0349dd 100644
--- a/src/cc65/function.c
+++ b/src/cc65/function.c
@@ -646,11 +646,17 @@ void NewFunc (SymEntry* Func, FuncDesc* D)
/* Output the function exit code label */
g_defcodelabel (F_GetRetLab (CurrentFunc));
- /* Restore the register variables */
- F_RestoreRegVars (CurrentFunc);
+ /* Restore the register variables (not necessary for the main function in
+ ** cc65 mode)
+ */
+ int CleanupOnExit = (IS_Get (&Standard) != STD_CC65) ||
+ !F_IsMainFunc (CurrentFunc);
+ if (CleanupOnExit) {
+ F_RestoreRegVars (CurrentFunc);
+ }
/* Generate the exit code */
- g_leave ();
+ g_leave (CleanupOnExit);
/* Emit references to imports/exports */
EmitExternals ();
diff --git a/src/cc65/initdata.c b/src/cc65/initdata.c
index 82cebefc2..addc7421b 100644
--- a/src/cc65/initdata.c
+++ b/src/cc65/initdata.c
@@ -302,6 +302,13 @@ static unsigned ParsePointerInit (const Type* T)
/* Optional opening brace */
unsigned BraceCount = OpeningCurlyBraces (0);
+ /* We warn if an initializer for a scalar contains braces, because this is
+ ** quite unusual and often a sign for some problem in the input.
+ */
+ if (BraceCount > 0) {
+ Warning ("Braces around scalar initializer");
+ }
+
/* Expression */
ExprDesc ED = NoCodeConstExpr (hie1);
TypeConversion (&ED, T);
diff --git a/src/cc65/locals.c b/src/cc65/locals.c
index 34d762324..08e41918e 100644
--- a/src/cc65/locals.c
+++ b/src/cc65/locals.c
@@ -111,15 +111,12 @@ static void ParseRegisterDecl (Declarator* Decl, int Reg)
/* Get the size of the variable */
unsigned Size = SizeOf (Decl->Type);
- /* Save the current contents of the register variable on stack */
- F_AllocLocalSpace (CurrentFunc);
- g_save_regvars (Reg, Size);
-
- /* Add the symbol to the symbol table. We do that now, because for register
- ** variables the current stack pointer is implicitly used as location for
- ** the save area.
+ /* Check if this is the main function and we are in cc65 mode. If so, we
+ ** won't save the old contents of the register variables since in cc65
+ ** mode main() may not be called recursively.
*/
- Sym = AddLocalSym (Decl->Ident, Decl->Type, Decl->StorageClass, Reg);
+ int SaveRegVars = (IS_Get (&Standard) != STD_CC65) ||
+ !F_IsMainFunc (CurrentFunc);
/* Check for an optional initialization */
if (CurTok.Tok == TOK_ASSIGN) {
@@ -127,6 +124,25 @@ static void ParseRegisterDecl (Declarator* Decl, int Reg)
/* Skip the '=' */
NextToken ();
+ /* If the register variable is initialized, the initialization code may
+ ** access other already declared variables. This means that we have to
+ ** allocate them now.
+ */
+ F_AllocLocalSpace (CurrentFunc);
+
+ /* Save the current contents of the register variable on stack. This is
+ ** not necessary for the main function.
+ */
+ if (SaveRegVars) {
+ g_save_regvars (Reg, Size);
+ }
+
+ /* Add the symbol to the symbol table. We do that now, because for
+ ** register variables the current stack pointer is implicitly used
+ ** as location for the save area (maybe unused in case of main()).
+ */
+ Sym = AddLocalSym (Decl->Ident, Decl->Type, Decl->StorageClass, Reg);
+
/* Special handling for compound types */
if (IsCompound) {
@@ -173,6 +189,21 @@ static void ParseRegisterDecl (Declarator* Decl, int Reg)
/* Mark the variable as referenced */
Sym->Flags |= SC_REF;
+ } else {
+
+ /* Save the current contents of the register variable on stack. This is
+ ** not necessary for the main function.
+ */
+ if (SaveRegVars) {
+ F_AllocLocalSpace (CurrentFunc);
+ g_save_regvars (Reg, Size);
+ }
+
+ /* Add the symbol to the symbol table. We do that now, because for
+ ** register variables the current stack pointer is implicitly used
+ ** as location for the save area (maybe unused in case of main()).
+ */
+ Sym = AddLocalSym (Decl->Ident, Decl->Type, Decl->StorageClass, Reg);
}
/* Cannot allocate a variable of unknown size */
diff --git a/src/cc65/main.c b/src/cc65/main.c
index 7dc5417f6..47435757c 100644
--- a/src/cc65/main.c
+++ b/src/cc65/main.c
@@ -91,7 +91,7 @@ static void Usage (void)
" -Os\t\t\t\tInline some standard functions\n"
" -T\t\t\t\tInclude source as comment\n"
" -V\t\t\t\tPrint the compiler version number\n"
- " -W warning[,...]\t\tSuppress warnings\n"
+ " -W [-+]warning[,...]\t\tControl warnings ('-' disables, '+' enables)\n"
" -d\t\t\t\tDebug mode\n"
" -g\t\t\t\tAdd debug info to object file\n"
" -h\t\t\t\tHelp (this text)\n"
diff --git a/src/cc65/ppexpr.c b/src/cc65/ppexpr.c
index 8d8c0b65d..dc6803f91 100644
--- a/src/cc65/ppexpr.c
+++ b/src/cc65/ppexpr.c
@@ -726,7 +726,7 @@ static void PPhieQuest (PPExpr* Expr)
PPhieQuest (&Expr3);
/* Set the result */
- Expr->IVal = Expr->IVal ? Expr2.IVal != 0 : Expr3.IVal != 0;
+ Expr->IVal = Expr->IVal ? Expr2.IVal : Expr3.IVal;
/* Restore evaluation as before */
PPEvaluationEnabled = PPEvaluationEnabledPrev;
diff --git a/src/cc65/pragma.c b/src/cc65/pragma.c
index b9394494b..ee71b42d8 100644
--- a/src/cc65/pragma.c
+++ b/src/cc65/pragma.c
@@ -68,70 +68,67 @@ typedef enum {
PRAGMA_ALIGN,
PRAGMA_ALLOW_EAGER_INLINE,
PRAGMA_BSS_NAME,
- PRAGMA_BSSSEG, /* obsolete */
PRAGMA_CHARMAP,
PRAGMA_CHECK_STACK,
- PRAGMA_CHECKSTACK, /* obsolete */
PRAGMA_CODE_NAME,
- PRAGMA_CODESEG, /* obsolete */
PRAGMA_CODESIZE,
PRAGMA_DATA_NAME,
- PRAGMA_DATASEG, /* obsolete */
PRAGMA_INLINE_STDFUNCS,
PRAGMA_LOCAL_STRINGS,
PRAGMA_MESSAGE,
PRAGMA_OPTIMIZE,
PRAGMA_REGISTER_VARS,
PRAGMA_REGVARADDR,
- PRAGMA_REGVARS, /* obsolete */
PRAGMA_RODATA_NAME,
- PRAGMA_RODATASEG, /* obsolete */
PRAGMA_SIGNED_CHARS,
- PRAGMA_SIGNEDCHARS, /* obsolete */
PRAGMA_STATIC_LOCALS,
- PRAGMA_STATICLOCALS, /* obsolete */
PRAGMA_WARN,
PRAGMA_WRAPPED_CALL,
PRAGMA_WRITABLE_STRINGS,
PRAGMA_ZPSYM,
- PRAGMA_COUNT
} pragma_t;
/* Pragma table */
static const struct Pragma {
const char* Key; /* Keyword */
pragma_t Tok; /* Token */
-} Pragmas[PRAGMA_COUNT] = {
+} Pragmas[] = {
{ "align", PRAGMA_ALIGN },
{ "allow-eager-inline", PRAGMA_ALLOW_EAGER_INLINE },
+ { "allow_eager_inline", PRAGMA_ALLOW_EAGER_INLINE },
{ "bss-name", PRAGMA_BSS_NAME },
- { "bssseg", PRAGMA_BSSSEG }, /* obsolete */
+ { "bss_name", PRAGMA_BSS_NAME },
{ "charmap", PRAGMA_CHARMAP },
{ "check-stack", PRAGMA_CHECK_STACK },
- { "checkstack", PRAGMA_CHECKSTACK }, /* obsolete */
+ { "check_stack", PRAGMA_CHECK_STACK },
{ "code-name", PRAGMA_CODE_NAME },
- { "codeseg", PRAGMA_CODESEG }, /* obsolete */
+ { "code_name", PRAGMA_CODE_NAME },
{ "codesize", PRAGMA_CODESIZE },
{ "data-name", PRAGMA_DATA_NAME },
- { "dataseg", PRAGMA_DATASEG }, /* obsolete */
+ { "data_name", PRAGMA_DATA_NAME },
{ "inline-stdfuncs", PRAGMA_INLINE_STDFUNCS },
+ { "inline_stdfuncs", PRAGMA_INLINE_STDFUNCS },
{ "local-strings", PRAGMA_LOCAL_STRINGS },
+ { "local_strings", PRAGMA_LOCAL_STRINGS },
{ "message", PRAGMA_MESSAGE },
{ "optimize", PRAGMA_OPTIMIZE },
{ "register-vars", PRAGMA_REGISTER_VARS },
+ { "register_vars", PRAGMA_REGISTER_VARS },
{ "regvaraddr", PRAGMA_REGVARADDR },
- { "regvars", PRAGMA_REGVARS }, /* obsolete */
{ "rodata-name", PRAGMA_RODATA_NAME },
- { "rodataseg", PRAGMA_RODATASEG }, /* obsolete */
+ { "rodata_name", PRAGMA_RODATA_NAME },
{ "signed-chars", PRAGMA_SIGNED_CHARS },
- { "signedchars", PRAGMA_SIGNEDCHARS }, /* obsolete */
+ { "signed_chars", PRAGMA_SIGNED_CHARS },
{ "static-locals", PRAGMA_STATIC_LOCALS },
- { "staticlocals", PRAGMA_STATICLOCALS }, /* obsolete */
+ { "static_locals", PRAGMA_STATIC_LOCALS },
{ "warn", PRAGMA_WARN },
{ "wrapped-call", PRAGMA_WRAPPED_CALL },
+ { "wrapped_call", PRAGMA_WRAPPED_CALL },
{ "writable-strings", PRAGMA_WRITABLE_STRINGS },
+ { "writable_strings", PRAGMA_WRITABLE_STRINGS },
{ "zpsym", PRAGMA_ZPSYM },
};
+#define PRAGMA_COUNT (sizeof (Pragmas) / sizeof (Pragmas[0]))
/* Result of ParsePushPop */
typedef enum {
@@ -402,22 +399,18 @@ static void ApplySegNamePragma (pragma_t Token, int PushPop, const char* Name, u
switch (Token) {
case PRAGMA_CODE_NAME:
- case PRAGMA_CODESEG:
Seg = SEG_CODE;
break;
case PRAGMA_RODATA_NAME:
- case PRAGMA_RODATASEG:
Seg = SEG_RODATA;
break;
case PRAGMA_DATA_NAME:
- case PRAGMA_DATASEG:
Seg = SEG_DATA;
break;
case PRAGMA_BSS_NAME:
- case PRAGMA_BSSSEG:
Seg = SEG_BSS;
break;
@@ -933,9 +926,6 @@ static void ParsePragmaString (void)
FlagPragma (PES_STMT, Pragma, &B, &EagerlyInlineFuncs);
break;
- case PRAGMA_BSSSEG:
- Warning ("#pragma bssseg is obsolete, please use #pragma bss-name instead");
- /* FALLTHROUGH */
case PRAGMA_BSS_NAME:
/* TODO: PES_STMT or even PES_EXPR (PES_DECL) maybe? */
SegNamePragma (PES_FUNC, PRAGMA_BSS_NAME, &B);
@@ -945,17 +935,11 @@ static void ParsePragmaString (void)
CharMapPragma (PES_IMM, &B);
break;
- case PRAGMA_CHECKSTACK:
- Warning ("#pragma checkstack is obsolete, please use #pragma check-stack instead");
- /* FALLTHROUGH */
case PRAGMA_CHECK_STACK:
/* TODO: PES_SCOPE maybe? */
FlagPragma (PES_FUNC, Pragma, &B, &CheckStack);
break;
- case PRAGMA_CODESEG:
- Warning ("#pragma codeseg is obsolete, please use #pragma code-name instead");
- /* FALLTHROUGH */
case PRAGMA_CODE_NAME:
/* PES_FUNC is the only sensible option so far */
SegNamePragma (PES_FUNC, PRAGMA_CODE_NAME, &B);
@@ -966,9 +950,6 @@ static void ParsePragmaString (void)
IntPragma (PES_STMT, Pragma, &B, &CodeSizeFactor, 10, 1000);
break;
- case PRAGMA_DATASEG:
- Warning ("#pragma dataseg is obsolete, please use #pragma data-name instead");
- /* FALLTHROUGH */
case PRAGMA_DATA_NAME:
/* TODO: PES_STMT or even PES_EXPR (PES_DECL) maybe? */
SegNamePragma (PES_FUNC, PRAGMA_DATA_NAME, &B);
@@ -999,33 +980,21 @@ static void ParsePragmaString (void)
FlagPragma (PES_FUNC, Pragma, &B, &AllowRegVarAddr);
break;
- case PRAGMA_REGVARS:
- Warning ("#pragma regvars is obsolete, please use #pragma register-vars instead");
- /* FALLTHROUGH */
case PRAGMA_REGISTER_VARS:
/* TODO: PES_STMT or even PES_EXPR (PES_DECL) maybe? */
FlagPragma (PES_FUNC, Pragma, &B, &EnableRegVars);
break;
- case PRAGMA_RODATASEG:
- Warning ("#pragma rodataseg is obsolete, please use #pragma rodata-name instead");
- /* FALLTHROUGH */
case PRAGMA_RODATA_NAME:
/* TODO: PES_STMT or even PES_EXPR maybe? */
SegNamePragma (PES_FUNC, PRAGMA_RODATA_NAME, &B);
break;
- case PRAGMA_SIGNEDCHARS:
- Warning ("#pragma signedchars is obsolete, please use #pragma signed-chars instead");
- /* FALLTHROUGH */
case PRAGMA_SIGNED_CHARS:
/* TODO: PES_STMT or even PES_EXPR maybe? */
FlagPragma (PES_FUNC, Pragma, &B, &SignedChars);
break;
- case PRAGMA_STATICLOCALS:
- Warning ("#pragma staticlocals is obsolete, please use #pragma static-locals instead");
- /* FALLTHROUGH */
case PRAGMA_STATIC_LOCALS:
/* TODO: PES_STMT or even PES_EXPR (PES_DECL) maybe? */
FlagPragma (PES_FUNC, Pragma, &B, &StaticLocals);
diff --git a/src/cc65/preproc.c b/src/cc65/preproc.c
index 66cbb2a9d..d033520b8 100644
--- a/src/cc65/preproc.c
+++ b/src/cc65/preproc.c
@@ -2640,6 +2640,18 @@ static void DoDefine (void)
goto Error_Handler;
}
NextChar ();
+
+ } else {
+
+ /* Object like macro. Check ISO/IEC 9899:1999 (E) 6.10.3p3:
+ ** "There shall be white-space between the identifier and the
+ ** replacement list in the definition of an object-like macro."
+ ** Note: C89 doesn't have this constraint.
+ */
+ if (Std == STD_C99 && !IsSpace (CurC)) {
+ PPWarning ("ISO C99 requires whitespace after the macro name");
+ }
+
}
/* Remove whitespace and comments from the line, store the preprocessed
@@ -2812,11 +2824,30 @@ static void DoInclude (void)
InputType IT;
StrBuf Filename = AUTO_STRBUF_INITIALIZER;
- /* Macro-replace a single line with special support for */
- SB_Clear (MLine);
- PreprocessDirective (Line, MLine, MSM_TOK_HEADER);
+ /* Skip whitespace so the input pointer points to the argument */
+ SkipWhitespace (0);
- /* Read from the processed line */
+ /* We may have three forms of the #include directive:
+ **
+ ** - # include "q-char-sequence" new-line
+ ** - # include new-line
+ ** - # include pp-tokens new-line
+ **
+ ** The former two are processed as is while the latter is preprocessed and
+ ** must then resemble one of the first two forms.
+ */
+ if (CurC == '"' || CurC == '<') {
+ /* Copy the argument part over to MLine */
+ unsigned Start = SB_GetIndex (Line);
+ unsigned Length = SB_GetLen (Line) - Start;
+ SB_Slice (MLine, Line, Start, Length);
+ } else {
+ /* Macro-replace a single line with special support for */
+ SB_Clear (MLine);
+ PreprocessDirective (Line, MLine, MSM_TOK_HEADER);
+ }
+
+ /* Read from the copied/preprocessed line */
SB_Reset (MLine);
MLine = InitLine (MLine);
@@ -2894,7 +2925,7 @@ static unsigned GetLineDirectiveNum (void)
/* Ensure the buffer is terminated with a '\0' */
SB_Terminate (&Buf);
- if (SkipWhitespace (0) != 0 || CurC == '\0') {
+ if (SB_GetLen (&Buf) > 0) {
const char* Str = SB_GetConstBuf (&Buf);
if (Str[0] == '\0') {
PPWarning ("#line directive interprets number as decimal, not octal");
@@ -2910,9 +2941,10 @@ static unsigned GetLineDirectiveNum (void)
}
}
} else {
- PPError ("#line directive requires a simple decimal digit sequence");
+ PPError ("#line directive requires a decimal digit sequence");
ClearLine ();
}
+ SkipWhitespace (0);
/* Done with the buffer */
SB_Done (&Buf);
diff --git a/src/cc65/scanner.c b/src/cc65/scanner.c
index 6b5235679..879925c7c 100644
--- a/src/cc65/scanner.c
+++ b/src/cc65/scanner.c
@@ -1267,7 +1267,7 @@ static int CloseBrace (Collection* C, token_t Tok)
*/
{
if (CollCount (C) > 0) {
- token_t LastTok = (token_t)CollLast (C);
+ token_t LastTok = (token_t)(intptr_t)CollLast (C);
if (LastTok == Tok) {
CollPop (C);
NextToken ();
diff --git a/src/grc65/main.c b/src/grc65/main.c
index 7d31bfc52..5ef9e9645 100644
--- a/src/grc65/main.c
+++ b/src/grc65/main.c
@@ -231,9 +231,11 @@ static int findToken (const char * const *tokenTbl, const char *token)
/* takes as input table of tokens and token, returns position in table or -1 if not found */
int i;
- for (i = 0; tokenTbl[i][0]; i++) {
- if (strcmp (tokenTbl[i], token) == 0) {
- return i;
+ if (token != NULL) {
+ for (i = 0; tokenTbl[i][0]; i++) {
+ if (strcmp (tokenTbl[i], token) == 0) {
+ return i;
+ }
}
}
diff --git a/src/ld65/config.c b/src/ld65/config.c
index 6c1f6ad4c..947302e98 100644
--- a/src/ld65/config.c
+++ b/src/ld65/config.c
@@ -889,6 +889,7 @@ static void ParseO65 (void)
CfgOptionalAssign ();
/* Check which attribute was given */
+ CfgSymbol* Sym;
switch (AttrTok) {
case CFGTOK_EXPORT:
@@ -896,8 +897,11 @@ static void ParseO65 (void)
AttrFlags |= atExport;
/* We expect an identifier */
CfgAssureIdent ();
- /* Remember it as an export for later */
- NewCfgSymbol (CfgSymO65Export, GetStrBufId (&CfgSVal));
+ /* Remember it as an export for later. We do not support o65
+ * output for the 65816, so the address size is always 16 bit.
+ */
+ Sym = NewCfgSymbol (CfgSymO65Export, GetStrBufId (&CfgSVal));
+ Sym->AddrSize = ADDR_SIZE_ABS;
/* Eat the identifier token */
CfgNextTok ();
break;
@@ -907,8 +911,11 @@ static void ParseO65 (void)
AttrFlags |= atImport;
/* We expect an identifier */
CfgAssureIdent ();
- /* Remember it as an import for later */
- NewCfgSymbol (CfgSymO65Import, GetStrBufId (&CfgSVal));
+ /* Remember it as an import for later. We do not support o65
+ * output for the 65816, so the address size is always 16 bit.
+ */
+ Sym = NewCfgSymbol (CfgSymO65Import, GetStrBufId (&CfgSVal));
+ Sym->AddrSize = ADDR_SIZE_ABS;
/* Eat the identifier token */
CfgNextTok ();
break;
diff --git a/src/ld65/exports.c b/src/ld65/exports.c
index 9149f54d1..9fa0e4019 100644
--- a/src/ld65/exports.c
+++ b/src/ld65/exports.c
@@ -808,6 +808,15 @@ static int CmpExpName (const void* K1, const void* K2)
+static int CmpExpValue (const void* K1, const void* K2)
+/* Compare function for qsort */
+{
+ long Diff = GetExportVal (*(Export**)K1) - GetExportVal (*(Export**)K2);
+ return Diff < 0? -1 : Diff > 0? 1 : 0;
+}
+
+
+
static void CreateExportPool (void)
/* Create an array with pointer to all exports */
{
@@ -880,19 +889,25 @@ static char GetAddrSizeCode (unsigned char AddrSize)
-void PrintExportMapByName (FILE* F)
-/* Print an export map, sorted by symbol name, to the given file */
+static void PrintExportMap (Export** Pool, unsigned Count, FILE* F)
+/* Print an export map to the given file */
{
unsigned I;
- unsigned Count;
/* Print all exports */
- Count = 0;
- for (I = 0; I < ExpCount; ++I) {
- const Export* E = ExpPool [I];
+ unsigned Col = 0;
+ for (I = 0; I < Count; ++I) {
+ const Export* E = Pool [I];
- /* Print unreferenced symbols only if explictly requested */
- if (VerboseMap || E->ImpCount > 0 || SYM_IS_CONDES (E->Type)) {
+ /* Print unreferenced symbols only if explictly requested. If Expr is
+ ** NULL, the export is undefined. This happens for imports that don't
+ ** have a matching export, but if we have one of those, we don't come
+ ** here. It does also happen for imports that where satisfied from
+ ** elsewhere, like o65 imports defined in the linker config.
+ ** So ignore exports here that have an invalid Expr.
+ */
+ if (E->Expr != 0 &&
+ (VerboseMap || E->ImpCount > 0 || SYM_IS_CONDES (E->Type))) {
fprintf (F,
"%-25s %06lX %c%c%c%c ",
GetString (E->Name),
@@ -901,8 +916,8 @@ void PrintExportMapByName (FILE* F)
SYM_IS_LABEL (E->Type)? 'L' : 'E',
GetAddrSizeCode ((unsigned char) E->AddrSize),
SYM_IS_CONDES (E->Type)? 'I' : ' ');
- if (++Count == 2) {
- Count = 0;
+ if (++Col == 2) {
+ Col = 0;
fprintf (F, "\n");
}
}
@@ -912,13 +927,10 @@ void PrintExportMapByName (FILE* F)
-static int CmpExpValue (const void* I1, const void* I2)
-/* Compare function for qsort */
+void PrintExportMapByName (FILE* F)
+/* Print an export map, sorted by symbol name, to the given file */
{
- long V1 = GetExportVal (ExpPool [*(unsigned *)I1]);
- long V2 = GetExportVal (ExpPool [*(unsigned *)I2]);
-
- return V1 < V2 ? -1 : V1 == V2 ? 0 : 1;
+ PrintExportMap (ExpPool, ExpCount, F);
}
@@ -926,43 +938,16 @@ static int CmpExpValue (const void* I1, const void* I2)
void PrintExportMapByValue (FILE* F)
/* Print an export map, sorted by symbol value, to the given file */
{
- unsigned I;
- unsigned Count;
- unsigned *ExpValXlat;
+ /* Create a new pool that is sorted by value */
+ Export** Pool = xmalloc (ExpCount * sizeof (Export*));
+ memcpy (Pool, ExpPool, ExpCount * sizeof (Export*));
+ qsort (Pool, ExpCount, sizeof (Export*), CmpExpValue);
- /* Create a translation table where the symbols are sorted by value. */
- ExpValXlat = xmalloc (ExpCount * sizeof (unsigned));
- for (I = 0; I < ExpCount; ++I) {
- /* Initialize table with current sort order. */
- ExpValXlat [I] = I;
- }
+ /* Print the exports */
+ PrintExportMap (Pool, ExpCount, F);
- /* Sort them by value */
- qsort (ExpValXlat, ExpCount, sizeof (unsigned), CmpExpValue);
-
- /* Print all exports */
- Count = 0;
- for (I = 0; I < ExpCount; ++I) {
- const Export* E = ExpPool [ExpValXlat [I]];
-
- /* Print unreferenced symbols only if explictly requested */
- if (VerboseMap || E->ImpCount > 0 || SYM_IS_CONDES (E->Type)) {
- fprintf (F,
- "%-25s %06lX %c%c%c%c ",
- GetString (E->Name),
- GetExportVal (E),
- E->ImpCount? 'R' : ' ',
- SYM_IS_LABEL (E->Type)? 'L' : 'E',
- GetAddrSizeCode ((unsigned char) E->AddrSize),
- SYM_IS_CONDES (E->Type)? 'I' : ' ');
- if (++Count == 2) {
- Count = 0;
- fprintf (F, "\n");
- }
- }
- }
- fprintf (F, "\n");
- xfree (ExpValXlat);
+ /* Free the allocated buffer */
+ xfree (Pool);
}
diff --git a/src/sim65/6502.c b/src/sim65/6502.c
index 9d2c93da8..448e81669 100644
--- a/src/sim65/6502.c
+++ b/src/sim65/6502.c
@@ -12,6 +12,8 @@
/* EMail: uz@cc65.org */
/* */
/* Mar-2017, Christian Krueger, added support for 65SC02 */
+/* Dec-2023, Carlo Bramini, rewritten for better maintenance and added */
+/* support for undocumented opcodes for 6502 */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
@@ -44,7 +46,337 @@
#include "6502.h"
#include "paravirt.h"
+/*
+ 6502 opcode map:
+
+ x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF
+0x BRK ORA --- SLO NOP ORA ASL SLO PHP ORA ASL ANC NOP ORA ASL SLO
+ inx inx zp zp zp zp imm acc imm abs abs abs abs
+
+1x BPL ORA --- SLO NOP ORA ASL SLO CLC ORA NOP SLO NOP ORA ASL SLO
+ rel iny iny zpx zpx zpx zpy aby aby abx abx abx abx
+
+2x JSR AND --- RLA BIT AND ROL RLA PLP AND ROL ANC BIT AND ROL RLA
+ abs inx inx zp zp zp zp imm acc imm abs abs abs abs
+
+3x BMI AND --- RLA NOP AND ROL RLA SEC AND NOP RLA NOP AND ROL RLA
+ rel iny iny zpx zpx zpx zpy aby aby abx abx abx abx
+
+4x RTI EOR --- SRE NOP EOR LSR SRE PHA EOR LSR ASR JMP EOR LSR SRE
+ inx inx zp zp zp zp imm acc imm abs abs abs abs
+
+5x BVC EOR --- SRE NOP EOR LSR SRE CLI EOR NOP SRE NOP EOR LSR SRE
+ rel iny iny zpx zpx zpx zpx aby aby abx abx abx abx
+
+6x RTS ADC --- RRA NOP ADC ROR RRA PLA ADC ROR ARR JMP ADC ROR RRA
+ inx inx zp zp zp zp imm acc imm ind abs abs abs
+
+7x BVS ADC --- RRA NOP ADC ROR RRA SEI ADC NOP RRA NOP ADC ROR RRA
+ rel iny iny zpx zpx zpx zpx aby aby abx abx abx abx
+
+8x NOP STA NOP SAX STY STA STX SAX DEY NOP TXA ANE STY STA STX SAX
+ imm inx imm inx zp zp zp zp imm imm abs abs abs abs
+
+9x BCC STA --- SHA STY STA STX SAX TYA STA TXS TAS SHY STA SHX SHA
+ rel iny iny zpx zpx zpy zpy aby aby abx abx aby aby
+
+Ax LDY LDA LDX LAX LDY LDA LDX LAX TAY LDA TAX LXA LDY LDA LDX LAX
+ imm inx imm inx zp zp zp zp imm imm abs abs abs abs
+
+Bx BCS LDA --- LAX LDY LDA LDX LAX CLV LDA TSX LAS LDY LDA LDX LAX
+ rel iny iny zpx zpx zpy zpy aby aby abx abx aby aby
+
+Cx CPY CMP NOP DCP CPY CMP DEC DCP INY CMP DEX SBX CPY CMP DEC DCP
+ imm inx imm inx zp zp zp zp imm imm abs abs abs abs
+
+Dx BNE CMP --- DCP NOP CMP DEC DCP CLD CMP NOP DCP NOP CMP DEC DCP
+ rel iny iny zpx zpx zpx zpx aby zpx aby abx abx abx abx
+
+Ex CPX SBC NOP ISC CPX SBC INC ISC INX SBC NOP SBC CPX SBC INC ISC
+ imm inx imm inx zp zp zp zp imm imm abs abs abs abs
+
+Fx BEQ SBC --- ISC NOP SBC INC ISC SED SBC NOP ISC NOP SBC INC ISC
+ rel iny iny zpx zpx zpx zpx aby zpx aby abx abx abx abx
+
+--- = CPU JAM/HALT
+
+*/
+
+/*
+
+65xx ILLEGAL INSTRUCTIONS
+
+
+* SLO: shift left the contents of a memory location and then OR the result with
+ the accumulator.
+
+Address mode | opcode | cycles | N V B D I Z C
+-------------+--------+--------+ FLAGS: X . . . . X X
+SLO abs | 0Fh | 6 |
+SLO abs,X | 1Fh | 7 |
+SLO abs,Y | 1Bh | 7 |
+SLO zp | 07h | 5 |
+SLO zp,X | 17h | 6 |
+SLO (zp,X) | 03h | 8 |
+SLO (zp),Y | 13h | 8 |
+-------------+--------+--------+
+
+
+* RLA: rotate left the contents of a memory location and then AND the result with
+ the accumulator.
+
+Address mode | opcode | cycles | N V B D I Z C
+-------------+--------+--------+ FLAGS: X . . . . X X
+RLA abs | 2Fh | 6 |
+RLA abs,X | 3Fh | 7 |
+RLA abs,Y | 3Bh | 7 |
+RLA zp | 27h | 5 |
+RLA zp,X | 37h | 6 |
+RLA (zp,X) | 23h | 8 |
+RLA (zp),Y | 33h | 8 |
+-------------+--------+--------+
+
+
+* SRE: shift right the contents of a memory location and then X-OR the result
+ with the accumulator.
+
+Address mode | opcode | cycles | N V B D I Z C
+-------------+--------+--------+ FLAGS: X . . . . X X
+SRE abs | 4Fh | 6 |
+SRE abs,X | 5Fh | 7 |
+SRE abs,Y | 5Bh | 7 |
+SRE zp | 47h | 5 |
+SRE zp,X | 57h | 6 |
+SRE (zp,X) | 43h | 8 |
+SRE (zp),Y | 53h | 8 |
+-------------+--------+--------+
+
+
+* RRA: rotate right the contents of a memory location and then adds with carry
+ the result with the accumulator.
+
+Address mode | opcode | cycles | N V B D I Z C
+-------------+--------+--------+ FLAGS: X X . . . X X
+RRA abs | 6Fh | 6 |
+RRA abs,X | 7Fh | 7 |
+RRA abs,Y | 7Bh | 7 |
+RRA zp | 67h | 5 |
+RRA zp,X | 77h | 6 |
+RRA (zp,X) | 63h | 8 |
+RRA (zp),Y | 73h | 8 |
+-------------+--------+--------+
+
+
+* SAX: calculate AND between the A and X registers (without changing the
+ contents of the registers) and stores the result in memory.
+ Flags into P register are not modified.
+
+Address mode | opcode | cycles | N V B D I Z C
+-------------+--------+--------+ FLAGS: . . . . . . .
+SAX abs | 8Fh | 4 |
+SAX zp | 87h | 3 |
+SAX zp,Y | 97h | 4 |
+SAX (zp,X) | 83h | 6 |
+-------------+--------+--------+
+
+
+* LAX: loads both the accumulator and the X register with the content of a memory
+ location.
+
+Address mode | opcode | cycles | N V B D I Z C
+-------------+--------+--------+ FLAGS: X . . . . X .
+LAX abs | AFh | 4 |
+LAX abs,Y | BFh | 4* | * = adds +1 if page cross is detected.
+LAX zp | A7h | 3 |
+LAX zp,Y | B7h | 4 |
+LAX (zp,X) | A3h | 6 |
+LAX (zp),Y | B3h | 5* |
+-------------+--------+--------+
+
+
+* DCP: decrements the contents of a memory location and then compares the result
+ with the accumulator.
+
+Address mode | opcode | cycles | N V B D I Z C
+-------------+--------+--------+ FLAGS: X . . . . X X
+DCP abs | CFh | 6 |
+DCP abs,X | DFh | 7 |
+DCP abs,Y | DBh | 7 |
+DCP zp | C7h | 5 |
+DCP zp,X | D7h | 6 |
+DCP (zp,X) | C3h | 8 |
+DCP (zp),Y | D3h | 8 |
+-------------+--------+--------+
+
+
+* ISC: increments the contents of a memory location and then subtract with carry
+ the result from the accumulator.
+
+Address mode | opcode | cycles | N V B D I Z C
+-------------+--------+--------+ FLAGS: X X . . . X X
+ISC abs | EFh | 6 |
+ISC abs,X | FFh | 7 |
+ISC abs,Y | FBh | 7 |
+ISC zp | E7h | 5 |
+ISC zp,X | F7h | 6 |
+ISC (zp,X) | E3h | 8 |
+ISC (zp),Y | F3h | 8 |
+-------------+--------+--------+
+
+
+* ASR: calculates the AND between the accumulator and an immediate value and then
+ shift right the result.
+
+Address mode | opcode | cycles | N V B D I Z C
+-------------+--------+--------+ FLAGS: X . . . . X X
+ASR #imm | 4Bh | 2 |
+-------------+--------+--------+
+
+
+* ARR: calculates the AND between the accumulator and an immediate value and then
+ rotate right the result.
+
+Address mode | opcode | cycles | N V B D I Z C
+-------------+--------+--------+ FLAGS: X . . . . X X
+ARR #imm | 6Bh | 2 |
+-------------+--------+--------+
+
+
+* ANE: calculates the OR of the accumulator with an unstable constant, then it does
+ an AND with the X register and an immediate value.
+ The unstable constant varies with temperature, the production batch and
+ maybe other factors. Experimental measures assume its value to 0xEF.
+
+Address mode | opcode | cycles | N V B D I Z C
+-------------+--------+--------+ FLAGS: X . . . . X .
+ANE #imm | 8Bh | 2 |
+-------------+--------+--------+
+
+
+* LXA: calculates the OR of the accumulator with an unstable constant, then it does
+ an AND with an immediate value. The result is copied into the X register and
+ the accumulator.
+ The unstable constant varies with temperature, the production batch and
+ maybe other factors. Experimental measures assume its value to 0xEE.
+
+Address mode | opcode | cycles | N V B D I Z C
+-------------+--------+--------+ FLAGS: X . . . . X .
+LXA #imm | ABh | 2 |
+-------------+--------+--------+
+
+
+* SBX: calculates the AND of the accumulator with the X register and the subtracts
+ an immediate value.
+
+Address mode | opcode | cycles | N V B D I Z C
+-------------+--------+--------+ FLAGS: X . . . . X X
+SBX #imm | CBh | 2 |
+-------------+--------+--------+
+
+
+* NOP: No-Operation.
+
+Address mode | opcode | cycles | N V B D I Z C
+-------------+--------+--------+ FLAGS: . . . . . . .
+NOP | 1Ah | 2 |
+NOP | 3Ah | 2 | * = adds +1 if page cross is detected.
+NOP | 5Ah | 2 |
+NOP | 7Ah | 2 |
+NOP | DAh | 2 |
+NOP | FAh | 2 |
+NOP #imm | 80h | 2 |
+NOP #imm | 82h | 2 |
+NOP #imm | 89h | 2 |
+NOP #imm | C2h | 2 |
+NOP #imm | E2h | 2 |
+NOP zp | 04h | 3 |
+NOP zp,x | 14h | 4 |
+NOP zp,x | 34h | 4 |
+NOP zp | 44h | 3 |
+NOP zp,x | 54h | 4 |
+NOP zp | 64h | 3 |
+NOP zp,x | 74h | 4 |
+NOP zp,x | D4h | 4 |
+NOP zp,x | F4h | 4 |
+NOP abs | 0Ch | 4 |
+NOP abs,x | 1Ch | 4* |
+NOP abs,x | 3Ch | 4* |
+NOP abs,x | 5Ch | 4* |
+NOP abs,x | 7Ch | 4* |
+NOP abs,x | DCh | 4* |
+NOP abs,x | FCh | 4* |
+-------------+--------+--------+
+
+
+* TAS: calculates the AND of the accumulator with the X register and stores the result
+ into the stack pointer. Then, it calculates the AND of the result with the
+ high byte of the memory pointer plus 1 and it stores the final result in memory.
+
+Address mode | opcode | cycles | N V B D I Z C
+-------------+--------+--------+ FLAGS: . . . . . . .
+TAS abs,y | 9Bh | 5 |
+-------------+--------+--------+
+
+
+* SHY: calculates the AND of the Y register with the high byte of the memory pointer
+ plus 1 and it stores the final result in memory.
+
+Address mode | opcode | cycles | N V B D I Z C
+-------------+--------+--------+ FLAGS: . . . . . . .
+SHY abs,x | 9Ch | 5 |
+-------------+--------+--------+
+
+
+* SHX: calculates the AND of the X register with the high byte of the memory pointer
+ plus 1 and it stores the final result in memory.
+
+Address mode | opcode | cycles | N V B D I Z C
+-------------+--------+--------+ FLAGS: . . . . . . .
+SHX abs,y | 9Eh | 5 |
+-------------+--------+--------+
+
+
+* SHA: calculates the AND of the accumulator with the X register with the high byte
+ of the memory pointer plus 1 and it stores the final result in memory.
+
+Address mode | opcode | cycles | N V B D I Z C
+-------------+--------+--------+ FLAGS: . . . . . . .
+SHX abs,y | 9Fh | 5 |
+SHX (zp),y | 93h | 6 |
+-------------+--------+--------+
+
+
+* ANC: calculates the AND of the accumulator with an immediate value and then
+ updates the status of N and Z bits of the status register.
+ The N flag is also copied into the Carry flag.
+
+Address mode | opcode | cycles | N V B D I Z C
+-------------+--------+--------+ FLAGS: X . . . . X X
+ANC #imm | 0Bh | 2 |
+ANC #imm | 2Bh | 2 |
+-------------+--------+--------+
+
+
+* LAS: calculates the contents of a memory location with the contents of the
+stack pointer register and it stores the result in the accumulator, the X
+register, and the stack pointer.
+
+Address mode | opcode | cycles | N V B D I Z C
+-------------+--------+--------+ FLAGS: X . . . . X .
+LAS abs,y | BBh | 4* |
+-------------+--------+--------+ * = adds +1 if page cross is detected.
+
+
+* SBC: alias of the official SBC opcode.
+
+Address mode | opcode | cycles | N V B D I Z C
+-------------+--------+--------+ FLAGS: X X . . . X X
+SBC #imm | EBh | 2 |
+-------------+--------+--------+
+
+
+*/
/*****************************************************************************/
/* Data */
@@ -113,118 +445,223 @@ static unsigned HaveIRQRequest;
/* Test for page cross */
#define PAGE_CROSS(addr,offs) ((((addr) & 0xFF) + offs) >= 0x100)
-/* #imm */
-#define AC_OP_IMM(op) \
- Cycles = 2; \
- Regs.AC = Regs.AC op MemReadByte (Regs.PC+1); \
- TEST_ZF (Regs.AC); \
- TEST_SF (Regs.AC); \
- Regs.PC += 2
+/* Address operators */
/* zp */
-#define AC_OP_ZP(op) \
- Cycles = 3; \
- Regs.AC = Regs.AC op MemReadByte (MemReadByte (Regs.PC+1)); \
- TEST_ZF (Regs.AC); \
- TEST_SF (Regs.AC); \
+#define ADR_ZP(ad) \
+ ad = MemReadByte (Regs.PC+1); \
Regs.PC += 2
/* zp,x */
-#define AC_OP_ZPX(op) \
- unsigned char ZPAddr; \
- Cycles = 4; \
- ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR; \
- Regs.AC = Regs.AC op MemReadByte (ZPAddr); \
- TEST_ZF (Regs.AC); \
- TEST_SF (Regs.AC); \
+#define ADR_ZPX(ad) \
+ ad = (MemReadByte (Regs.PC+1) + Regs.XR) & 0xFF; \
Regs.PC += 2
/* zp,y */
-#define AC_OP_ZPY(op) \
- unsigned char ZPAddr; \
- Cycles = 4; \
- ZPAddr = MemReadByte (Regs.PC+1) + Regs.YR; \
- Regs.AC = Regs.AC op MemReadByte (ZPAddr); \
- TEST_ZF (Regs.AC); \
- TEST_SF (Regs.AC); \
+#define ADR_ZPY(ad) \
+ ad = (MemReadByte (Regs.PC+1) + Regs.YR) & 0xFF; \
Regs.PC += 2
/* abs */
-#define AC_OP_ABS(op) \
- unsigned Addr; \
- Cycles = 4; \
- Addr = MemReadWord (Regs.PC+1); \
- Regs.AC = Regs.AC op MemReadByte (Addr); \
- TEST_ZF (Regs.AC); \
- TEST_SF (Regs.AC); \
+#define ADR_ABS(ad) \
+ ad = MemReadWord (Regs.PC+1); \
Regs.PC += 3
/* abs,x */
-#define AC_OP_ABSX(op) \
- unsigned Addr; \
- Cycles = 4; \
- Addr = MemReadWord (Regs.PC+1); \
- if (PAGE_CROSS (Addr, Regs.XR)) { \
+#define ADR_ABSX(ad) \
+ ad = MemReadWord (Regs.PC+1); \
+ if (PAGE_CROSS (ad, Regs.XR)) { \
++Cycles; \
} \
- Regs.AC = Regs.AC op MemReadByte (Addr + Regs.XR); \
- TEST_ZF (Regs.AC); \
- TEST_SF (Regs.AC); \
+ ad += Regs.XR; \
Regs.PC += 3
/* abs,y */
-#define AC_OP_ABSY(op) \
- unsigned Addr; \
- Cycles = 4; \
- Addr = MemReadWord (Regs.PC+1); \
- if (PAGE_CROSS (Addr, Regs.YR)) { \
+#define ADR_ABSY(ad) \
+ ad = MemReadWord (Regs.PC+1); \
+ if (PAGE_CROSS (ad, Regs.YR)) { \
++Cycles; \
} \
- Regs.AC = Regs.AC op MemReadByte (Addr + Regs.YR); \
- TEST_ZF (Regs.AC); \
- TEST_SF (Regs.AC); \
+ ad += Regs.YR; \
Regs.PC += 3
/* (zp,x) */
-#define AC_OP_ZPXIND(op) \
- unsigned char ZPAddr; \
- unsigned Addr; \
- Cycles = 6; \
- ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR; \
- Addr = MemReadZPWord (ZPAddr); \
- Regs.AC = Regs.AC op MemReadByte (Addr); \
- TEST_ZF (Regs.AC); \
- TEST_SF (Regs.AC); \
+#define ADR_ZPXIND(ad) \
+ ad = (MemReadByte (Regs.PC+1) + Regs.XR) & 0xFF; \
+ ad = MemReadZPWord (ad); \
Regs.PC += 2
/* (zp),y */
-#define AC_OP_ZPINDY(op) \
- unsigned char ZPAddr; \
- unsigned Addr; \
- Cycles = 5; \
- ZPAddr = MemReadByte (Regs.PC+1); \
- Addr = MemReadZPWord (ZPAddr); \
- if (PAGE_CROSS (Addr, Regs.YR)) { \
+#define ADR_ZPINDY(ad) \
+ ad = MemReadZPWord (MemReadByte (Regs.PC+1)); \
+ if (PAGE_CROSS (ad, Regs.YR)) { \
++Cycles; \
} \
- Addr += Regs.YR; \
- Regs.AC = Regs.AC op MemReadByte (Addr); \
- TEST_ZF (Regs.AC); \
- TEST_SF (Regs.AC); \
+ ad += Regs.YR; \
Regs.PC += 2
/* (zp) */
-#define AC_OP_ZPIND(op) \
- unsigned char ZPAddr; \
- unsigned Addr; \
- Cycles = 5; \
- ZPAddr = MemReadByte (Regs.PC+1); \
- Addr = MemReadZPWord (ZPAddr); \
- Regs.AC = Regs.AC op MemReadByte (Addr); \
- TEST_ZF (Regs.AC); \
- TEST_SF (Regs.AC); \
+#define ADR_ZPIND(ad) \
+ ad = MemReadZPWord (MemReadByte (Regs.PC+1)); \
Regs.PC += 2
+/* Address operators (no penalty on page cross) */
+
+/* abs,x - no penalty */
+#define ADR_ABSX_NP(ad) \
+ ad = MemReadWord (Regs.PC+1); \
+ ad += Regs.XR; \
+ Regs.PC += 3
+
+/* abs,y - no penalty */
+#define ADR_ABSY_NP(ad) \
+ ad = MemReadWord (Regs.PC+1); \
+ ad += Regs.YR; \
+ Regs.PC += 3
+
+/* (zp),y - no penalty */
+#define ADR_ZPINDY_NP(ad) \
+ ad = MemReadZPWord (MemReadByte (Regs.PC+1)); \
+ ad += Regs.YR; \
+ Regs.PC += 2
+
+
+
+/* Memory operators */
+
+/* #imm */
+#define MEM_AD_OP_IMM(op) \
+ op = MemReadByte (Regs.PC+1); \
+ Regs.PC += 2
+
+/* zp / zp,x / zp,y / abs / abs,x / abs,y / (zp,x) / (zp),y / (zp) */
+#define MEM_AD_OP(mode, ad, op) \
+ ADR_##mode(ad); \
+ op = MemReadByte (ad)
+
+/* ALU opcode helpers */
+
+/* Execution cycles for ALU opcodes */
+#define ALU_CY_ZP 3
+#define ALU_CY_ZPX 4
+#define ALU_CY_ZPY 4
+#define ALU_CY_ABS 4
+#define ALU_CY_ABSX 4
+#define ALU_CY_ABSY 4
+#define ALU_CY_ZPXIND 6
+#define ALU_CY_ZPINDY 5
+#define ALU_CY_ZPIND 5
+
+/* #imm */
+#define ALU_OP_IMM(op) \
+ unsigned char immediate; \
+ MEM_AD_OP_IMM(immediate); \
+ Cycles = 2; \
+ op (immediate)
+
+/* zp / zp,x / zp,y / abs / abs,x / abs,y / (zp,x) / (zp),y / (zp) */
+#define ALU_OP(mode, op) \
+ unsigned address, operand; \
+ Cycles = ALU_CY_##mode; \
+ MEM_AD_OP (mode, address, operand); \
+ op (operand)
+
+/* Store opcode helpers */
+
+/* Execution cycles for store opcodes */
+#define STO_CY_ZP 3
+#define STO_CY_ZPX 4
+#define STO_CY_ZPY 4
+#define STO_CY_ABS 4
+#define STO_CY_ABSX 5
+#define STO_CY_ABSY 5
+#define STO_CY_ZPXIND 6
+#define STO_CY_ZPINDY 6
+#define STO_CY_ZPIND 5
+
+/* zp / zp,x / zp,y / abs / abs,x / abs,y / (zp,x) / (zp),y / (zp) */
+#define STO_OP(mode, op) \
+ unsigned address; \
+ Cycles = STO_CY_##mode; \
+ ADR_##mode (address); \
+ MemWriteByte(address, op)
+
+/* zp / zp,x / zp,y / abs / abs,x / abs,y / (zp,x) / (zp),y / (zp) */
+#define STO_CB(mode, cb) \
+ unsigned address, operand; \
+ Cycles = STO_CY_##mode; \
+ ADR_##mode (address); \
+ cb (operand); \
+ MemWriteByte(address, operand)
+
+/* Read-Modify-Write opcode helpers */
+
+/* Execution cycles for R-M-W opcodes */
+#define RMW_CY_ZP 5
+#define RMW_CY_ZPX 6
+#define RMW_CY_ZPY 6
+#define RMW_CY_ABS 6
+#define RMW_CY_ABSX 7
+#define RMW_CY_ABSY 7
+#define RMW_CY_ZPXIND 6
+#define RMW_CY_ZPINDY 5
+#define RMW_CY_ZPIND 5
+
+#define RMW_CY_ABSX_NP RMW_CY_ABSX
+#define RMW_CY_ABSY_NP RMW_CY_ABSY
+#define RMW_CY_ZPINDY_NP RMW_CY_ZPINDY
+
+/* zp / zp,x / zp,y / abs / abs,x / abs,y / (zp,x) / (zp),y / (zp) */
+#define MEM_OP(mode, op) \
+ unsigned address, operand; \
+ Cycles = RMW_CY_##mode; \
+ MEM_AD_OP (mode, address, operand); \
+ op (operand); \
+ MemWriteByte (address, (unsigned char)operand)
+
+/* 2 x Read-Modify-Write opcode helpers (illegal opcodes) */
+
+/* Execution cycles for 2 x R-M-W opcodes */
+#define RMW2_CY_ZP 5
+#define RMW2_CY_ZPX 6
+#define RMW2_CY_ZPY 6
+#define RMW2_CY_ABS 6
+#define RMW2_CY_ABSX 7
+#define RMW2_CY_ABSY 7
+#define RMW2_CY_ZPXIND 8
+#define RMW2_CY_ZPINDY 8
+
+/* zp / zp,x / zp,y / abs / abs,x / abs,y / (zp,x) / (zp),y */
+#define ILLx2_OP(mode, op) \
+ unsigned address; \
+ unsigned operand; \
+ Cycles = RMW2_CY_##mode; \
+ MEM_AD_OP (mode, address, operand); \
+ op (operand); \
+ MemWriteByte (address, (unsigned char)operand)
+
+/* AC opcode helpers */
+
+/* #imm */
+#define AC_OP_IMM(op) \
+ unsigned char immediate; \
+ MEM_AD_OP_IMM(immediate); \
+ Cycles = 2; \
+ Regs.AC = Regs.AC op immediate; \
+ TEST_ZF (Regs.AC); \
+ TEST_SF (Regs.AC)
+
+/* zp / zp,x / zp,y / abs / abs,x / abs,y / (zp,x) / (zp),y / (zp) */
+#define AC_OP(mode, op) \
+ unsigned address; \
+ unsigned operand; \
+ Cycles = ALU_CY_##mode; \
+ MEM_AD_OP(mode, address, operand); \
+ Regs.AC = Regs.AC op operand; \
+ TEST_ZF (Regs.AC); \
+ TEST_SF (Regs.AC)
+
+
/* ADC */
#define ADC(v) \
do { \
@@ -248,7 +685,7 @@ static unsigned HaveIRQRequest;
} \
TEST_CF (Regs.AC); \
SET_OF ((res < -128) || (res > 127)); \
- if (CPU != CPU_6502) { \
+ if (CPU == CPU_65C02) { \
++Cycles; \
} \
} else { \
@@ -271,7 +708,7 @@ static unsigned HaveIRQRequest;
++Cycles; \
Offs = (signed char) MemReadByte (Regs.PC+1); \
OldPCH = PCH; \
- Regs.PC += 2 + (int) Offs; \
+ Regs.PC = (Regs.PC + 2 + (int) Offs) & 0xFFFF; \
if (PCH != OldPCH) { \
++Cycles; \
} \
@@ -280,14 +717,22 @@ static unsigned HaveIRQRequest;
}
/* compares */
-#define CMP(v1, v2) \
+#define COMPARE(v1, v2) \
do { \
unsigned Result = v1 - v2; \
- TEST_ZF (Result & 0xFF); \
+ TEST_ZF (Result); \
TEST_SF (Result); \
SET_CF (Result <= 0xFF); \
} while (0)
+#define CPX(operand) \
+ COMPARE (Regs.XR, operand)
+
+#define CPY(operand) \
+ COMPARE (Regs.YR, operand)
+
+#define CMP(operand) \
+ COMPARE (Regs.AC, operand)
/* ROL */
#define ROL(Val) \
@@ -309,38 +754,243 @@ static unsigned HaveIRQRequest;
TEST_ZF (Val); \
TEST_SF (Val)
-/* SBC */
-#define SBC(v) \
+/* ASL */
+#define ASL(Val) \
+ SET_CF (Val & 0x80); \
+ Val = (Val << 1) & 0xFF; \
+ TEST_ZF (Val); \
+ TEST_SF (Val)
+
+/* LSR */
+#define LSR(Val) \
+ SET_CF (Val & 0x01); \
+ Val >>= 1; \
+ TEST_ZF (Val); \
+ TEST_SF (Val)
+
+/* INC */
+#define INC(Val) \
+ Val = (Val + 1) & 0xFF; \
+ TEST_ZF (Val); \
+ TEST_SF (Val)
+
+/* DEC */
+#define DEC(Val) \
+ Val = (Val - 1) & 0xFF; \
+ TEST_ZF (Val); \
+ TEST_SF (Val)
+
+/* SLO */
+#define SLO(Val) \
+ Val <<= 1; \
+ SET_CF (Val & 0x100); \
+ Regs.AC |= Val; \
+ Regs.AC &= 0xFF; \
+ TEST_ZF (Regs.AC); \
+ TEST_SF (Regs.AC)
+
+/* RLA */
+#define RLA(Val) \
+ Val <<= 1; \
+ if (GET_CF ()) { \
+ Val |= 0x01; \
+ } \
+ SET_CF (Val & 0x100); \
+ Regs.AC &= Val; \
+ TEST_ZF (Regs.AC); \
+ TEST_SF (Regs.AC)
+
+/* SRE */
+#define SRE(Val) \
+ SET_CF (Val & 0x01); \
+ Val >>= 1; \
+ Regs.AC ^= Val; \
+ TEST_ZF (Regs.AC); \
+ TEST_SF (Regs.AC)
+
+/* RRA */
+#define RRA(Val) \
+ if (GET_CF ()) { \
+ Val |= 0x100; \
+ } \
+ SET_CF (Val & 0x01); \
+ Val >>= 1; \
+ ADC (Val)
+
+/* BIT */
+#define BIT(Val) \
+ SET_SF (Val & 0x80); \
+ SET_OF (Val & 0x40); \
+ SET_ZF ((Val & Regs.AC) == 0)
+
+/* LDA */
+#define LDA(Val) \
+ Regs.AC = Val; \
+ TEST_SF (Val); \
+ TEST_ZF (Val)
+
+/* LDX */
+#define LDX(Val) \
+ Regs.XR = Val; \
+ TEST_SF (Val); \
+ TEST_ZF (Val)
+
+/* LDY */
+#define LDY(Val) \
+ Regs.YR = Val; \
+ TEST_SF (Val); \
+ TEST_ZF (Val)
+
+/* LAX */
+#define LAX(Val) \
+ Regs.AC = Val; \
+ Regs.XR = Val; \
+ TEST_SF (Val); \
+ TEST_ZF (Val)
+
+/* TSB */
+#define TSB(Val) \
+ SET_ZF ((Val & Regs.AC) == 0); \
+ Val |= Regs.AC
+
+/* TRB */
+#define TRB(Val) \
+ SET_ZF ((Val & Regs.AC) == 0); \
+ Val &= ~Regs.AC
+
+/* DCP */
+#define DCP(Val) \
+ Val = (Val - 1) & 0xFF; \
+ COMPARE (Regs.AC, Val)
+
+/* ISC */
+#define ISC(Val) \
+ Val = (Val + 1) & 0xFF; \
+ SBC(Val)
+
+/* ASR */
+#define ASR(Val) \
+ Regs.AC &= Val; \
+ LSR(Regs.AC)
+
+/* ARR */
+#define ARR(Val) \
do { \
- unsigned old = Regs.AC; \
- unsigned rhs = (v & 0xFF); \
+ unsigned tmp = Regs.AC & Val; \
+ Val = tmp >> 1; \
+ if (GET_CF ()) { \
+ Val |= 0x80; \
+ } \
if (GET_DF ()) { \
- unsigned lo; \
- int res; \
- lo = (old & 0x0F) - (rhs & 0x0F) + GET_CF () - 1; \
- if (lo & 0x80) { \
- lo = ((lo - 0x06) & 0x0F) - 0x10; \
+ SET_SF (GET_CF ()); \
+ TEST_ZF (Val); \
+ SET_OF ((Val ^ tmp) & 0x40); \
+ if (((tmp & 0x0f) + (tmp & 0x01)) > 0x05) { \
+ Val = (Val & 0xf0) | ((Val + 0x06) & 0x0f); \
} \
- Regs.AC = (old & 0xF0) - (rhs & 0xF0) + lo; \
- if (Regs.AC & 0x80) { \
- Regs.AC -= 0x60; \
+ if (((tmp & 0xf0) + (tmp & 0x10)) > 0x50) { \
+ Val = (Val & 0x0f) | ((Val + 0x60) & 0xf0); \
+ SET_CF(1); \
+ } else { \
+ SET_CF(0); \
} \
- res = Regs.AC - rhs + (!GET_CF ()); \
- TEST_ZF (res); \
- TEST_SF (res); \
- SET_CF (res <= 0xFF); \
- SET_OF (((old^rhs) & (old^res) & 0x80)); \
- if (CPU != CPU_6502) { \
+ if (CPU == CPU_65C02) { \
++Cycles; \
} \
} else { \
- Regs.AC -= rhs + (!GET_CF ()); \
- TEST_ZF (Regs.AC); \
- TEST_SF (Regs.AC); \
- SET_CF (Regs.AC <= 0xFF); \
- SET_OF (((old^rhs) & (old^Regs.AC) & 0x80)); \
- Regs.AC &= 0xFF; \
+ TEST_SF (Val); \
+ TEST_ZF (Val); \
+ SET_CF (Val & 0x40); \
+ SET_OF ((Val & 0x40) ^ ((Val & 0x20) << 1)); \
} \
+ Regs.AC = Val; \
+ } while (0);
+
+/* ANE */
+#define ANE(Val) \
+ Val = (Regs.AC | 0xEF) & Regs.XR & Val; \
+ Regs.AC = Val; \
+ TEST_SF (Val); \
+ TEST_ZF (Val)
+
+/* LXA */
+#define LXA(Val) \
+ Val = (Regs.AC | 0xEE) & Val; \
+ Regs.AC = Val; \
+ Regs.XR = Val; \
+ TEST_SF (Val); \
+ TEST_ZF (Val)
+
+/* SBX */
+#define SBX(Val) \
+ do { \
+ unsigned tmp = (Regs.AC & Regs.XR) - (Val); \
+ SET_CF (tmp < 0x100); \
+ tmp &= 0xFF; \
+ Regs.XR = tmp; \
+ TEST_SF (tmp); \
+ TEST_ZF (tmp); \
+ } while (0);
+
+/* NOP */
+#define NOP(Val) \
+ (void)Val
+
+/* TAS */
+#define TAS(Val) \
+ Val = Regs.AC & Regs.XR; \
+ Regs.SP = Val; \
+ Val &= (address >> 8) + 1
+
+/* SHA */
+#define SHA(Val) \
+ Val = Regs.AC & Regs.XR & ((address >> 8) + 1)
+
+/* ANC */
+#define ANC(Val) \
+ Val = Regs.AC & Val; \
+ Regs.AC = Val; \
+ SET_CF (Val & 0x80); \
+ TEST_SF (Val); \
+ TEST_ZF (Val)
+
+
+/* LAS */
+#define LAS(Val) \
+ Val = Regs.SP & Val; \
+ Regs.AC = Val; \
+ Regs.XR = Val; \
+ Regs.SP = Val; \
+ TEST_SF (Val); \
+ TEST_ZF (Val)
+
+
+/* SBC */
+#define SBC(v) \
+ do { \
+ unsigned r_a = Regs.AC; \
+ unsigned src = (v) & 0xFF; \
+ unsigned ccc = (Regs.SR & CF) ^ CF; \
+ unsigned tmp = r_a - src - ccc; \
+ \
+ SET_CF(tmp < 0x100); \
+ TEST_SF(tmp); \
+ TEST_ZF(tmp); \
+ SET_OF((r_a ^ tmp) & (r_a ^ src) & 0x80); \
+ \
+ if (GET_DF ()) { \
+ unsigned low = (r_a & 0x0f) - (src & 0x0f) - ccc; \
+ tmp = (r_a & 0xf0) - (src & 0xf0); \
+ if (low & 0x10) { \
+ low -= 6; \
+ tmp -= 0x10; \
+ } \
+ tmp = (low & 0xf) | tmp; \
+ if (tmp & 0x100) { \
+ tmp -= 0x60; \
+ } \
+ } \
+ Regs.AC = tmp & 0xFF; \
} while (0)
@@ -368,7 +1018,7 @@ static void OPC_6502_00 (void)
PUSH (PCL);
PUSH (Regs.SR);
SET_IF (1);
- if (CPU != CPU_6502)
+ if (CPU == CPU_65C02)
{
SET_DF (0);
}
@@ -380,7 +1030,27 @@ static void OPC_6502_00 (void)
static void OPC_6502_01 (void)
/* Opcode $01: ORA (ind,x) */
{
- AC_OP_ZPXIND (|);
+ AC_OP (ZPXIND, |);
+}
+
+
+
+static void OPC_6502_03 (void)
+/* Opcode $03: SLO (zp,x) */
+{
+ ILLx2_OP (ZPXIND, SLO);
+}
+
+
+
+/* Aliases of opcode $04 */
+#define OPC_6502_44 OPC_6502_04
+#define OPC_6502_64 OPC_6502_04
+
+static void OPC_6502_04 (void)
+/* Opcode $04: NOP zp */
+{
+ ALU_OP (ZP, NOP);
}
@@ -388,14 +1058,7 @@ static void OPC_6502_01 (void)
static void OPC_65SC02_04 (void)
/* Opcode $04: TSB zp */
{
- unsigned char ZPAddr;
- unsigned char Val;
- Cycles = 5;
- ZPAddr = MemReadByte (Regs.PC+1);
- Val = MemReadByte (ZPAddr);
- SET_ZF ((Val & Regs.AC) == 0);
- MemWriteByte (ZPAddr, (unsigned char)(Val | Regs.AC));
- Regs.PC += 2;
+ MEM_OP (ZP, TSB);
}
@@ -403,7 +1066,7 @@ static void OPC_65SC02_04 (void)
static void OPC_6502_05 (void)
/* Opcode $05: ORA zp */
{
- AC_OP_ZP (|);
+ AC_OP (ZP, |);
}
@@ -411,16 +1074,15 @@ static void OPC_6502_05 (void)
static void OPC_6502_06 (void)
/* Opcode $06: ASL zp */
{
- unsigned char ZPAddr;
- unsigned Val;
- Cycles = 5;
- ZPAddr = MemReadByte (Regs.PC+1);
- Val = MemReadByte (ZPAddr) << 1;
- MemWriteByte (ZPAddr, (unsigned char) Val);
- TEST_ZF (Val & 0xFF);
- TEST_SF (Val);
- SET_CF (Val & 0x100);
- Regs.PC += 2;
+ MEM_OP (ZP, ASL);
+}
+
+
+
+static void OPC_6502_07 (void)
+/* Opcode $07: SLO zp */
+{
+ ILLx2_OP (ZP, SLO);
}
@@ -447,27 +1109,35 @@ static void OPC_6502_0A (void)
/* Opcode $0A: ASL a */
{
Cycles = 2;
- Regs.AC <<= 1;
- TEST_ZF (Regs.AC & 0xFF);
- TEST_SF (Regs.AC);
- SET_CF (Regs.AC & 0x100);
- Regs.AC &= 0xFF;
+ ASL(Regs.AC);
Regs.PC += 1;
}
+/* Aliases of opcode $0B */
+#define OPC_6502_2B OPC_6502_0B
+
+static void OPC_6502_0B (void)
+/* Opcode $0B: ANC #imm */
+{
+ ALU_OP_IMM (ANC);
+}
+
+
+
+static void OPC_6502_0C (void)
+/* Opcode $0C: NOP abs */
+{
+ ALU_OP (ABS, NOP);
+}
+
+
+
static void OPC_65SC02_0C (void)
/* Opcode $0C: TSB abs */
{
- unsigned Addr;
- unsigned char Val;
- Cycles = 6;
- Addr = MemReadWord (Regs.PC+1);
- Val = MemReadByte (Addr);
- SET_ZF ((Val & Regs.AC) == 0);
- MemWriteByte (Addr, (unsigned char) (Val | Regs.AC));
- Regs.PC += 3;
+ MEM_OP (ABS, TSB);
}
@@ -475,24 +1145,23 @@ static void OPC_65SC02_0C (void)
static void OPC_6502_0D (void)
/* Opcode $0D: ORA abs */
{
- AC_OP_ABS (|);
+ AC_OP (ABS, |);
}
static void OPC_6502_0E (void)
-/* Opcode $0E: ALS abs */
+/* Opcode $0E: ASL abs */
{
- unsigned Addr;
- unsigned Val;
- Cycles = 6;
- Addr = MemReadWord (Regs.PC+1);
- Val = MemReadByte (Addr) << 1;
- MemWriteByte (Addr, (unsigned char) Val);
- TEST_ZF (Val & 0xFF);
- TEST_SF (Val);
- SET_CF (Val & 0x100);
- Regs.PC += 3;
+ MEM_OP (ABS, ASL);
+}
+
+
+
+static void OPC_6502_0F (void)
+/* Opcode $0F: SLO abs */
+{
+ ILLx2_OP (ABS, SLO);
}
@@ -508,7 +1177,7 @@ static void OPC_6502_10 (void)
static void OPC_6502_11 (void)
/* Opcode $11: ORA (zp),y */
{
- AC_OP_ZPINDY (|);
+ AC_OP (ZPINDY, |);
}
@@ -516,7 +1185,30 @@ static void OPC_6502_11 (void)
static void OPC_65SC02_12 (void)
/* Opcode $12: ORA (zp) */
{
- AC_OP_ZPIND (|);
+ AC_OP (ZPIND, |);
+}
+
+
+
+static void OPC_6502_13 (void)
+/* Opcode $03: SLO (zp),y */
+{
+ ILLx2_OP (ZPINDY, SLO);
+}
+
+
+
+/* Aliases of opcode $14 */
+#define OPC_6502_34 OPC_6502_14
+#define OPC_6502_54 OPC_6502_14
+#define OPC_6502_74 OPC_6502_14
+#define OPC_6502_D4 OPC_6502_14
+#define OPC_6502_F4 OPC_6502_14
+
+static void OPC_6502_14 (void)
+/* Opcode $04: NOP zp,x */
+{
+ ALU_OP (ZPX, NOP);
}
@@ -524,14 +1216,7 @@ static void OPC_65SC02_12 (void)
static void OPC_65SC02_14 (void)
/* Opcode $14: TRB zp */
{
- unsigned char ZPAddr;
- unsigned char Val;
- Cycles = 5;
- ZPAddr = MemReadByte (Regs.PC+1);
- Val = MemReadByte (ZPAddr);
- SET_ZF ((Val & Regs.AC) == 0);
- MemWriteByte (ZPAddr, (unsigned char)(Val & ~Regs.AC));
- Regs.PC += 2;
+ MEM_OP (ZP, TRB);
}
@@ -539,7 +1224,7 @@ static void OPC_65SC02_14 (void)
static void OPC_6502_15 (void)
/* Opcode $15: ORA zp,x */
{
- AC_OP_ZPX (|);
+ AC_OP (ZPX, |);
}
@@ -547,16 +1232,15 @@ static void OPC_6502_15 (void)
static void OPC_6502_16 (void)
/* Opcode $16: ASL zp,x */
{
- unsigned char ZPAddr;
- unsigned Val;
- Cycles = 6;
- ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
- Val = MemReadByte (ZPAddr) << 1;
- MemWriteByte (ZPAddr, (unsigned char) Val);
- TEST_ZF (Val & 0xFF);
- TEST_SF (Val);
- SET_CF (Val & 0x100);
- Regs.PC += 2;
+ MEM_OP (ZPX, ASL);
+}
+
+
+
+static void OPC_6502_17 (void)
+/* Opcode $17: SLO zp,x */
+{
+ ILLx2_OP (ZPX, SLO);
}
@@ -574,7 +1258,7 @@ static void OPC_6502_18 (void)
static void OPC_6502_19 (void)
/* Opcode $19: ORA abs,y */
{
- AC_OP_ABSY (|);
+ AC_OP (ABSY, |);
}
@@ -583,25 +1267,39 @@ static void OPC_65SC02_1A (void)
/* Opcode $1A: INC a */
{
Cycles = 2;
- Regs.AC = (Regs.AC + 1) & 0xFF;
- TEST_ZF (Regs.AC);
- TEST_SF (Regs.AC);
+ INC(Regs.AC);
Regs.PC += 1;
}
+static void OPC_6502_1B (void)
+/* Opcode $1B: SLO abs,y */
+{
+ ILLx2_OP (ABSY, SLO);
+}
+
+
+
+/* Aliases of opcode $1C */
+#define OPC_6502_3C OPC_6502_1C
+#define OPC_6502_5C OPC_6502_1C
+#define OPC_6502_7C OPC_6502_1C
+#define OPC_6502_DC OPC_6502_1C
+#define OPC_6502_FC OPC_6502_1C
+
+static void OPC_6502_1C (void)
+/* Opcode $1C: NOP abs,x */
+{
+ ALU_OP (ABSX, NOP);
+}
+
+
+
static void OPC_65SC02_1C (void)
/* Opcode $1C: TRB abs */
{
- unsigned Addr;
- unsigned char Val;
- Cycles = 6;
- Addr = MemReadWord (Regs.PC+1);
- Val = MemReadByte (Addr);
- SET_ZF ((Val & Regs.AC) == 0);
- MemWriteByte (Addr, (unsigned char) (Val & ~Regs.AC));
- Regs.PC += 3;
+ MEM_OP (ABS, TRB);
}
@@ -609,7 +1307,7 @@ static void OPC_65SC02_1C (void)
static void OPC_6502_1D (void)
/* Opcode $1D: ORA abs,x */
{
- AC_OP_ABSX (|);
+ AC_OP (ABSX, |);
}
@@ -617,18 +1315,23 @@ static void OPC_6502_1D (void)
static void OPC_6502_1E (void)
/* Opcode $1E: ASL abs,x */
{
- unsigned Addr;
- unsigned Val;
- Cycles = 7;
- Addr = MemReadWord (Regs.PC+1) + Regs.XR;
- if (CPU != CPU_6502 && !PAGE_CROSS (Addr, Regs.XR))
- --Cycles;
- Val = MemReadByte (Addr) << 1;
- MemWriteByte (Addr, (unsigned char) Val);
- TEST_ZF (Val & 0xFF);
- TEST_SF (Val);
- SET_CF (Val & 0x100);
- Regs.PC += 3;
+ MEM_OP (ABSX, ASL);
+}
+
+
+
+static void OPC_65C02_1E (void)
+/* Opcode $1E: ASL abs,x */
+{
+ MEM_OP (ABSX_NP, ASL);
+}
+
+
+
+static void OPC_6502_1F (void)
+/* Opcode $1F: SLO abs,x */
+{
+ ILLx2_OP (ABSX, SLO);
}
@@ -652,23 +1355,23 @@ static void OPC_6502_20 (void)
static void OPC_6502_21 (void)
/* Opcode $21: AND (zp,x) */
{
- AC_OP_ZPXIND (&);
+ AC_OP (ZPXIND, &);
+}
+
+
+
+static void OPC_6502_23 (void)
+/* Opcode $23: RLA (zp,x) */
+{
+ ILLx2_OP (ZPXIND, RLA);
}
static void OPC_6502_24 (void)
-/* Opcode $24: BIT zp */
{
- unsigned char ZPAddr;
- unsigned char Val;
- Cycles = 3;
- ZPAddr = MemReadByte (Regs.PC+1);
- Val = MemReadByte (ZPAddr);
- SET_SF (Val & 0x80);
- SET_OF (Val & 0x40);
- SET_ZF ((Val & Regs.AC) == 0);
- Regs.PC += 2;
+/* Opcode $24: BIT zp */
+ ALU_OP (ZP, BIT);
}
@@ -676,7 +1379,7 @@ static void OPC_6502_24 (void)
static void OPC_6502_25 (void)
/* Opcode $25: AND zp */
{
- AC_OP_ZP (&);
+ AC_OP (ZP, &);
}
@@ -684,14 +1387,15 @@ static void OPC_6502_25 (void)
static void OPC_6502_26 (void)
/* Opcode $26: ROL zp */
{
- unsigned char ZPAddr;
- unsigned Val;
- Cycles = 5;
- ZPAddr = MemReadByte (Regs.PC+1);
- Val = MemReadByte (ZPAddr);
- ROL (Val);
- MemWriteByte (ZPAddr, Val);
- Regs.PC += 2;
+ MEM_OP (ZP, ROL);
+}
+
+
+
+static void OPC_6502_27 (void)
+/* Opcode $27: RLA zp */
+{
+ ILLx2_OP (ZP, RLA);
}
@@ -730,15 +1434,7 @@ static void OPC_6502_2A (void)
static void OPC_6502_2C (void)
/* Opcode $2C: BIT abs */
{
- unsigned Addr;
- unsigned char Val;
- Cycles = 4;
- Addr = MemReadWord (Regs.PC+1);
- Val = MemReadByte (Addr);
- SET_SF (Val & 0x80);
- SET_OF (Val & 0x40);
- SET_ZF ((Val & Regs.AC) == 0);
- Regs.PC += 3;
+ ALU_OP (ABS, BIT);
}
@@ -746,7 +1442,7 @@ static void OPC_6502_2C (void)
static void OPC_6502_2D (void)
/* Opcode $2D: AND abs */
{
- AC_OP_ABS (&);
+ AC_OP (ABS, &);
}
@@ -754,14 +1450,15 @@ static void OPC_6502_2D (void)
static void OPC_6502_2E (void)
/* Opcode $2E: ROL abs */
{
- unsigned Addr;
- unsigned Val;
- Cycles = 6;
- Addr = MemReadWord (Regs.PC+1);
- Val = MemReadByte (Addr);
- ROL (Val);
- MemWriteByte (Addr, Val);
- Regs.PC += 3;
+ MEM_OP (ABS, ROL);
+}
+
+
+
+static void OPC_6502_2F (void)
+/* Opcode $2F: RLA abs */
+{
+ ILLx2_OP (ABS, RLA);
}
@@ -777,7 +1474,7 @@ static void OPC_6502_30 (void)
static void OPC_6502_31 (void)
/* Opcode $31: AND (zp),y */
{
- AC_OP_ZPINDY (&);
+ AC_OP (ZPINDY, &);
}
@@ -785,7 +1482,15 @@ static void OPC_6502_31 (void)
static void OPC_65SC02_32 (void)
/* Opcode $32: AND (zp) */
{
- AC_OP_ZPIND (&);
+ AC_OP (ZPIND, &);
+}
+
+
+
+static void OPC_6502_33 (void)
+/* Opcode $33: RLA (zp),y */
+{
+ ILLx2_OP (ZPINDY, RLA);
}
@@ -793,15 +1498,7 @@ static void OPC_65SC02_32 (void)
static void OPC_65SC02_34 (void)
/* Opcode $34: BIT zp,x */
{
- unsigned char ZPAddr;
- unsigned char Val;
- Cycles = 4;
- ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
- Val = MemReadByte (ZPAddr);
- SET_SF (Val & 0x80);
- SET_OF (Val & 0x40);
- SET_ZF ((Val & Regs.AC) == 0);
- Regs.PC += 2;
+ ALU_OP (ZPX, BIT);
}
@@ -809,7 +1506,7 @@ static void OPC_65SC02_34 (void)
static void OPC_6502_35 (void)
/* Opcode $35: AND zp,x */
{
- AC_OP_ZPX (&);
+ AC_OP (ZPX, &);
}
@@ -817,14 +1514,15 @@ static void OPC_6502_35 (void)
static void OPC_6502_36 (void)
/* Opcode $36: ROL zp,x */
{
- unsigned char ZPAddr;
- unsigned Val;
- Cycles = 6;
- ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
- Val = MemReadByte (ZPAddr);
- ROL (Val);
- MemWriteByte (ZPAddr, Val);
- Regs.PC += 2;
+ MEM_OP (ZPX, ROL);
+}
+
+
+
+static void OPC_6502_37 (void)
+/* Opcode $37: RLA zp,x */
+{
+ ILLx2_OP (ZPX, RLA);
}
@@ -842,7 +1540,7 @@ static void OPC_6502_38 (void)
static void OPC_6502_39 (void)
/* Opcode $39: AND abs,y */
{
- AC_OP_ABSY (&);
+ AC_OP (ABSY, &);
}
@@ -851,28 +1549,24 @@ static void OPC_65SC02_3A (void)
/* Opcode $3A: DEC a */
{
Cycles = 2;
- Regs.AC = (Regs.AC - 1) & 0xFF;
- TEST_ZF (Regs.AC);
- TEST_SF (Regs.AC);
+ DEC (Regs.AC);
Regs.PC += 1;
}
+static void OPC_6502_3B (void)
+/* Opcode $3B: RLA abs,y */
+{
+ ILLx2_OP (ABSY, RLA);
+}
+
+
+
static void OPC_65SC02_3C (void)
/* Opcode $3C: BIT abs,x */
{
- unsigned Addr;
- unsigned char Val;
- Cycles = 4;
- Addr = MemReadWord (Regs.PC+1);
- if (PAGE_CROSS (Addr, Regs.XR))
- ++Cycles;
- Val = MemReadByte (Addr + Regs.XR);
- SET_SF (Val & 0x80);
- SET_OF (Val & 0x40);
- SET_ZF ((Val & Regs.AC) == 0);
- Regs.PC += 3;
+ ALU_OP (ABSX, BIT);
}
@@ -880,7 +1574,7 @@ static void OPC_65SC02_3C (void)
static void OPC_6502_3D (void)
/* Opcode $3D: AND abs,x */
{
- AC_OP_ABSX (&);
+ AC_OP (ABSX, &);
}
@@ -888,16 +1582,23 @@ static void OPC_6502_3D (void)
static void OPC_6502_3E (void)
/* Opcode $3E: ROL abs,x */
{
- unsigned Addr;
- unsigned Val;
- Cycles = 7;
- Addr = MemReadWord (Regs.PC+1) + Regs.XR;
- if (CPU != CPU_6502 && !PAGE_CROSS (Addr, Regs.XR))
- --Cycles;
- Val = MemReadByte (Addr);
- ROL (Val);
- MemWriteByte (Addr, Val);
- Regs.PC += 2;
+ MEM_OP (ABSX, ROL);
+}
+
+
+
+static void OPC_65C02_3E (void)
+/* Opcode $3E: ROL abs,x */
+{
+ MEM_OP (ABSX_NP, ROL);
+}
+
+
+
+static void OPC_6502_3F (void)
+/* Opcode $3B: RLA abs,x */
+{
+ ILLx2_OP (ABSX, RLA);
}
@@ -918,16 +1619,15 @@ static void OPC_6502_40 (void)
static void OPC_6502_41 (void)
/* Opcode $41: EOR (zp,x) */
{
- AC_OP_ZPXIND (^);
+ AC_OP (ZPXIND, ^);
}
-static void OPC_65C02_44 (void)
-/* Opcode $44: 'zp' 3 cycle NOP */
+static void OPC_6502_43 (void)
+/* Opcode $43: SRE (zp,x) */
{
- Cycles = 3;
- Regs.PC += 2;
+ ILLx2_OP (ZPXIND, SRE);
}
@@ -935,7 +1635,7 @@ static void OPC_65C02_44 (void)
static void OPC_6502_45 (void)
/* Opcode $45: EOR zp */
{
- AC_OP_ZP (^);
+ AC_OP (ZP, ^);
}
@@ -943,17 +1643,15 @@ static void OPC_6502_45 (void)
static void OPC_6502_46 (void)
/* Opcode $46: LSR zp */
{
- unsigned char ZPAddr;
- unsigned char Val;
- Cycles = 5;
- ZPAddr = MemReadByte (Regs.PC+1);
- Val = MemReadByte (ZPAddr);
- SET_CF (Val & 0x01);
- Val >>= 1;
- MemWriteByte (ZPAddr, Val);
- TEST_ZF (Val);
- TEST_SF (Val);
- Regs.PC += 2;
+ MEM_OP (ZP, LSR);
+}
+
+
+
+static void OPC_6502_47 (void)
+/* Opcode $47: SRE zp */
+{
+ ILLx2_OP (ZP, SRE);
}
@@ -980,15 +1678,20 @@ static void OPC_6502_4A (void)
/* Opcode $4A: LSR a */
{
Cycles = 2;
- SET_CF (Regs.AC & 0x01);
- Regs.AC >>= 1;
- TEST_ZF (Regs.AC);
- TEST_SF (Regs.AC);
+ LSR (Regs.AC);
Regs.PC += 1;
}
+static void OPC_6502_4B (void)
+/* Opcode $4B: ASR imm */
+{
+ ALU_OP_IMM (ASR);
+}
+
+
+
static void OPC_6502_4C (void)
/* Opcode $4C: JMP abs */
{
@@ -1003,7 +1706,7 @@ static void OPC_6502_4C (void)
static void OPC_6502_4D (void)
/* Opcode $4D: EOR abs */
{
- AC_OP_ABS (^);
+ AC_OP (ABS, ^);
}
@@ -1011,17 +1714,15 @@ static void OPC_6502_4D (void)
static void OPC_6502_4E (void)
/* Opcode $4E: LSR abs */
{
- unsigned Addr;
- unsigned char Val;
- Cycles = 6;
- Addr = MemReadWord (Regs.PC+1);
- Val = MemReadByte (Addr);
- SET_CF (Val & 0x01);
- Val >>= 1;
- MemWriteByte (Addr, Val);
- TEST_ZF (Val);
- TEST_SF (Val);
- Regs.PC += 3;
+ MEM_OP (ABS, LSR);
+}
+
+
+
+static void OPC_6502_4F (void)
+/* Opcode $4F: SRE abs */
+{
+ ILLx2_OP (ABS, SRE);
}
@@ -1037,7 +1738,7 @@ static void OPC_6502_50 (void)
static void OPC_6502_51 (void)
/* Opcode $51: EOR (zp),y */
{
- AC_OP_ZPINDY (^);
+ AC_OP (ZPINDY, ^);
}
@@ -1045,7 +1746,15 @@ static void OPC_6502_51 (void)
static void OPC_65SC02_52 (void)
/* Opcode $52: EOR (zp) */
{
- AC_OP_ZPIND (^);
+ AC_OP (ZPIND, ^);
+}
+
+
+
+static void OPC_6502_53 (void)
+/* Opcode $43: SRE (zp),y */
+{
+ ILLx2_OP (ZPINDY, SRE);
}
@@ -1053,7 +1762,7 @@ static void OPC_65SC02_52 (void)
static void OPC_6502_55 (void)
/* Opcode $55: EOR zp,x */
{
- AC_OP_ZPX (^);
+ AC_OP (ZPX, ^);
}
@@ -1061,17 +1770,15 @@ static void OPC_6502_55 (void)
static void OPC_6502_56 (void)
/* Opcode $56: LSR zp,x */
{
- unsigned char ZPAddr;
- unsigned char Val;
- Cycles = 6;
- ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
- Val = MemReadByte (ZPAddr);
- SET_CF (Val & 0x01);
- Val >>= 1;
- MemWriteByte (ZPAddr, Val);
- TEST_ZF (Val);
- TEST_SF (Val);
- Regs.PC += 2;
+ MEM_OP (ZPX, LSR);
+}
+
+
+
+static void OPC_6502_57 (void)
+/* Opcode $57: SRE zp,x */
+{
+ ILLx2_OP (ZPX, SRE);
}
@@ -1089,7 +1796,7 @@ static void OPC_6502_58 (void)
static void OPC_6502_59 (void)
/* Opcode $59: EOR abs,y */
{
- AC_OP_ABSY (^);
+ AC_OP (ABSY, ^);
}
@@ -1104,6 +1811,14 @@ static void OPC_65SC02_5A (void)
+static void OPC_6502_5B (void)
+/* Opcode $5B: SRE abs,y */
+{
+ ILLx2_OP (ABSY, SRE);
+}
+
+
+
static void OPC_65C02_5C (void)
/* Opcode $5C: 'Absolute' 8 cycle NOP */
{
@@ -1116,7 +1831,7 @@ static void OPC_65C02_5C (void)
static void OPC_6502_5D (void)
/* Opcode $5D: EOR abs,x */
{
- AC_OP_ABSX (^);
+ AC_OP (ABSX, ^);
}
@@ -1124,19 +1839,23 @@ static void OPC_6502_5D (void)
static void OPC_6502_5E (void)
/* Opcode $5E: LSR abs,x */
{
- unsigned Addr;
- unsigned char Val;
- Cycles = 7;
- Addr = MemReadWord (Regs.PC+1) + Regs.XR;
- if (CPU != CPU_6502 && !PAGE_CROSS (Addr, Regs.XR))
- --Cycles;
- Val = MemReadByte (Addr);
- SET_CF (Val & 0x01);
- Val >>= 1;
- MemWriteByte (Addr, Val);
- TEST_ZF (Val);
- TEST_SF (Val);
- Regs.PC += 3;
+ MEM_OP (ABSX, LSR);
+}
+
+
+
+static void OPC_65C02_5E (void)
+/* Opcode $5E: LSR abs,x */
+{
+ MEM_OP (ABSX_NP, LSR);
+}
+
+
+
+static void OPC_6502_5F (void)
+/* Opcode $5F: SRE abs,x */
+{
+ ILLx2_OP (ABSX, SRE);
}
@@ -1155,13 +1874,15 @@ static void OPC_6502_60 (void)
static void OPC_6502_61 (void)
/* Opcode $61: ADC (zp,x) */
{
- unsigned char ZPAddr;
- unsigned Addr;
- Cycles = 6;
- ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
- Addr = MemReadZPWord (ZPAddr);
- ADC (MemReadByte (Addr));
- Regs.PC += 2;
+ ALU_OP (ZPXIND, ADC);
+}
+
+
+
+static void OPC_6502_63 (void)
+/* Opcode $63: RRA (zp,x) */
+{
+ ILLx2_OP (ZPXIND, RRA);
}
@@ -1169,11 +1890,7 @@ static void OPC_6502_61 (void)
static void OPC_65SC02_64 (void)
/* Opcode $64: STZ zp */
{
- unsigned char ZPAddr;
- Cycles = 3;
- ZPAddr = MemReadByte (Regs.PC+1);
- MemWriteByte (ZPAddr, 0);
- Regs.PC += 2;
+ STO_OP (ZP, 0);
}
@@ -1181,11 +1898,7 @@ static void OPC_65SC02_64 (void)
static void OPC_6502_65 (void)
/* Opcode $65: ADC zp */
{
- unsigned char ZPAddr;
- Cycles = 3;
- ZPAddr = MemReadByte (Regs.PC+1);
- ADC (MemReadByte (ZPAddr));
- Regs.PC += 2;
+ ALU_OP (ZP, ADC);
}
@@ -1193,14 +1906,15 @@ static void OPC_6502_65 (void)
static void OPC_6502_66 (void)
/* Opcode $66: ROR zp */
{
- unsigned char ZPAddr;
- unsigned Val;
- Cycles = 5;
- ZPAddr = MemReadByte (Regs.PC+1);
- Val = MemReadByte (ZPAddr);
- ROR (Val);
- MemWriteByte (ZPAddr, Val);
- Regs.PC += 2;
+ MEM_OP (ZP, ROR);
+}
+
+
+
+static void OPC_6502_67 (void)
+/* Opcode $67: RRA zp */
+{
+ ILLx2_OP (ZP, RRA);
}
@@ -1220,9 +1934,7 @@ static void OPC_6502_68 (void)
static void OPC_6502_69 (void)
/* Opcode $69: ADC #imm */
{
- Cycles = 2;
- ADC (MemReadByte (Regs.PC+1));
- Regs.PC += 2;
+ ALU_OP_IMM (ADC);
}
@@ -1237,6 +1949,14 @@ static void OPC_6502_6A (void)
+static void OPC_6502_6B (void)
+/* Opcode $6B: ARR imm */
+{
+ ALU_OP_IMM (ARR);
+}
+
+
+
static void OPC_6502_6C (void)
/* Opcode $6C: JMP (ind) */
{
@@ -1285,11 +2005,7 @@ static void OPC_65C02_6C (void)
static void OPC_6502_6D (void)
/* Opcode $6D: ADC abs */
{
- unsigned Addr;
- Cycles = 4;
- Addr = MemReadWord (Regs.PC+1);
- ADC (MemReadByte (Addr));
- Regs.PC += 3;
+ ALU_OP (ABS, ADC);
}
@@ -1297,14 +2013,15 @@ static void OPC_6502_6D (void)
static void OPC_6502_6E (void)
/* Opcode $6E: ROR abs */
{
- unsigned Addr;
- unsigned Val;
- Cycles = 6;
- Addr = MemReadWord (Regs.PC+1);
- Val = MemReadByte (Addr);
- ROR (Val);
- MemWriteByte (Addr, Val);
- Regs.PC += 3;
+ MEM_OP (ABS, ROR);
+}
+
+
+
+static void OPC_6502_6F (void)
+/* Opcode $6F: RRA abs */
+{
+ ILLx2_OP (ABS, RRA);
}
@@ -1320,16 +2037,7 @@ static void OPC_6502_70 (void)
static void OPC_6502_71 (void)
/* Opcode $71: ADC (zp),y */
{
- unsigned char ZPAddr;
- unsigned Addr;
- Cycles = 5;
- ZPAddr = MemReadByte (Regs.PC+1);
- Addr = MemReadZPWord (ZPAddr);
- if (PAGE_CROSS (Addr, Regs.YR)) {
- ++Cycles;
- }
- ADC (MemReadByte (Addr + Regs.YR));
- Regs.PC += 2;
+ ALU_OP (ZPINDY, ADC);
}
@@ -1337,13 +2045,15 @@ static void OPC_6502_71 (void)
static void OPC_65SC02_72 (void)
/* Opcode $72: ADC (zp) */
{
- unsigned char ZPAddr;
- unsigned Addr;
- Cycles = 5;
- ZPAddr = MemReadByte (Regs.PC+1);
- Addr = MemReadZPWord (ZPAddr);
- ADC (MemReadByte (Addr));
- Regs.PC += 2;
+ ALU_OP (ZPIND, ADC);
+}
+
+
+
+static void OPC_6502_73 (void)
+/* Opcode $73: RRA (zp),y */
+{
+ ILLx2_OP (ZPINDY, RRA);
}
@@ -1351,11 +2061,7 @@ static void OPC_65SC02_72 (void)
static void OPC_65SC02_74 (void)
/* Opcode $74: STZ zp,x */
{
- unsigned char ZPAddr;
- Cycles = 4;
- ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
- MemWriteByte (ZPAddr, 0);
- Regs.PC += 2;
+ STO_OP (ZPX, 0);
}
@@ -1363,11 +2069,7 @@ static void OPC_65SC02_74 (void)
static void OPC_6502_75 (void)
/* Opcode $75: ADC zp,x */
{
- unsigned char ZPAddr;
- Cycles = 4;
- ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
- ADC (MemReadByte (ZPAddr));
- Regs.PC += 2;
+ ALU_OP (ZPX, ADC);
}
@@ -1375,14 +2077,15 @@ static void OPC_6502_75 (void)
static void OPC_6502_76 (void)
/* Opcode $76: ROR zp,x */
{
- unsigned char ZPAddr;
- unsigned Val;
- Cycles = 6;
- ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
- Val = MemReadByte (ZPAddr);
- ROR (Val);
- MemWriteByte (ZPAddr, Val);
- Regs.PC += 2;
+ MEM_OP (ZPX, ROR);
+}
+
+
+
+static void OPC_6502_77 (void)
+/* Opcode $77: RRA zp,x */
+{
+ ILLx2_OP (ZPX, RRA);
}
@@ -1400,14 +2103,7 @@ static void OPC_6502_78 (void)
static void OPC_6502_79 (void)
/* Opcode $79: ADC abs,y */
{
- unsigned Addr;
- Cycles = 4;
- Addr = MemReadWord (Regs.PC+1);
- if (PAGE_CROSS (Addr, Regs.YR)) {
- ++Cycles;
- }
- ADC (MemReadByte (Addr + Regs.YR));
- Regs.PC += 3;
+ ALU_OP (ABSY, ADC);
}
@@ -1424,6 +2120,14 @@ static void OPC_65SC02_7A (void)
+static void OPC_6502_7B (void)
+/* Opcode $7B: RRA abs,y */
+{
+ ILLx2_OP (ABSY, RRA);
+}
+
+
+
static void OPC_65SC02_7C (void)
/* Opcode $7C: JMP (ind,X) */
{
@@ -1441,14 +2145,7 @@ static void OPC_65SC02_7C (void)
static void OPC_6502_7D (void)
/* Opcode $7D: ADC abs,x */
{
- unsigned Addr;
- Cycles = 4;
- Addr = MemReadWord (Regs.PC+1);
- if (PAGE_CROSS (Addr, Regs.XR)) {
- ++Cycles;
- }
- ADC (MemReadByte (Addr + Regs.XR));
- Regs.PC += 3;
+ ALU_OP (ABSX, ADC);
}
@@ -1456,16 +2153,37 @@ static void OPC_6502_7D (void)
static void OPC_6502_7E (void)
/* Opcode $7E: ROR abs,x */
{
- unsigned Addr;
- unsigned Val;
- Cycles = 7;
- Addr = MemReadWord (Regs.PC+1) + Regs.XR;
- if (CPU != CPU_6502 && !PAGE_CROSS (Addr, Regs.XR))
- --Cycles;
- Val = MemReadByte (Addr);
- ROR (Val);
- MemWriteByte (Addr, Val);
- Regs.PC += 3;
+ MEM_OP (ABSX, ROR);
+}
+
+
+
+static void OPC_65C02_7E (void)
+/* Opcode $7E: ROR abs,x */
+{
+ MEM_OP (ABSX_NP, ROR);
+}
+
+
+
+static void OPC_6502_7F (void)
+/* Opcode $7F: RRA abs,x */
+{
+ ILLx2_OP (ABSX, RRA);
+}
+
+
+
+/* Aliases of opcode $80 */
+#define OPC_6502_82 OPC_6502_80
+#define OPC_6502_C2 OPC_6502_80
+#define OPC_6502_E2 OPC_6502_80
+#define OPC_6502_89 OPC_6502_80
+
+static void OPC_6502_80 (void)
+/* Opcode $80: NOP imm */
+{
+ ALU_OP_IMM (NOP);
}
@@ -1481,13 +2199,15 @@ static void OPC_65SC02_80 (void)
static void OPC_6502_81 (void)
/* Opcode $81: STA (zp,x) */
{
- unsigned char ZPAddr;
- unsigned Addr;
- Cycles = 6;
- ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
- Addr = MemReadZPWord (ZPAddr);
- MemWriteByte (Addr, Regs.AC);
- Regs.PC += 2;
+ STO_OP (ZPXIND, Regs.AC);
+}
+
+
+
+static void OPC_6502_83 (void)
+/* Opcode $83: SAX (zp,x) */
+{
+ STO_OP (ZPXIND, Regs.AC & Regs.XR);
}
@@ -1495,11 +2215,7 @@ static void OPC_6502_81 (void)
static void OPC_6502_84 (void)
/* Opcode $84: STY zp */
{
- unsigned char ZPAddr;
- Cycles = 3;
- ZPAddr = MemReadByte (Regs.PC+1);
- MemWriteByte (ZPAddr, Regs.YR);
- Regs.PC += 2;
+ STO_OP (ZP, Regs.YR);
}
@@ -1507,11 +2223,7 @@ static void OPC_6502_84 (void)
static void OPC_6502_85 (void)
/* Opcode $85: STA zp */
{
- unsigned char ZPAddr;
- Cycles = 3;
- ZPAddr = MemReadByte (Regs.PC+1);
- MemWriteByte (ZPAddr, Regs.AC);
- Regs.PC += 2;
+ STO_OP (ZP, Regs.AC);
}
@@ -1519,11 +2231,15 @@ static void OPC_6502_85 (void)
static void OPC_6502_86 (void)
/* Opcode $86: STX zp */
{
- unsigned char ZPAddr;
- Cycles = 3;
- ZPAddr = MemReadByte (Regs.PC+1);
- MemWriteByte (ZPAddr, Regs.XR);
- Regs.PC += 2;
+ STO_OP (ZP, Regs.XR);
+}
+
+
+
+static void OPC_6502_87 (void)
+/* Opcode $87: SAX zp */
+{
+ STO_OP (ZP, Regs.AC & Regs.XR);
}
@@ -1532,9 +2248,7 @@ static void OPC_6502_88 (void)
/* Opcode $88: DEY */
{
Cycles = 2;
- Regs.YR = (Regs.YR - 1) & 0xFF;
- TEST_ZF (Regs.YR);
- TEST_SF (Regs.YR);
+ DEC (Regs.YR);
Regs.PC += 1;
}
@@ -1543,13 +2257,7 @@ static void OPC_6502_88 (void)
static void OPC_65SC02_89 (void)
/* Opcode $89: BIT #imm */
{
- unsigned char Val;
- Cycles = 2;
- Val = MemReadByte (Regs.PC+1);
- SET_SF (Val & 0x80);
- SET_OF (Val & 0x40);
- SET_ZF ((Val & Regs.AC) == 0);
- Regs.PC += 2;
+ ALU_OP_IMM (BIT);
}
@@ -1566,14 +2274,18 @@ static void OPC_6502_8A (void)
+static void OPC_6502_8B (void)
+/* Opcode $8B: ANE imm */
+{
+ ALU_OP_IMM (ANE);
+}
+
+
+
static void OPC_6502_8C (void)
/* Opcode $8C: STY abs */
{
- unsigned Addr;
- Cycles = 4;
- Addr = MemReadWord (Regs.PC+1);
- MemWriteByte (Addr, Regs.YR);
- Regs.PC += 3;
+ STO_OP (ABS, Regs.YR);
}
@@ -1581,11 +2293,7 @@ static void OPC_6502_8C (void)
static void OPC_6502_8D (void)
/* Opcode $8D: STA abs */
{
- unsigned Addr;
- Cycles = 4;
- Addr = MemReadWord (Regs.PC+1);
- MemWriteByte (Addr, Regs.AC);
- Regs.PC += 3;
+ STO_OP (ABS, Regs.AC);
}
@@ -1593,11 +2301,15 @@ static void OPC_6502_8D (void)
static void OPC_6502_8E (void)
/* Opcode $8E: STX abs */
{
- unsigned Addr;
- Cycles = 4;
- Addr = MemReadWord (Regs.PC+1);
- MemWriteByte (Addr, Regs.XR);
- Regs.PC += 3;
+ STO_OP (ABS, Regs.XR);
+}
+
+
+
+static void OPC_6502_8F (void)
+/* Opcode $8F: SAX abs */
+{
+ STO_OP (ABS, Regs.AC & Regs.XR);
}
@@ -1613,13 +2325,7 @@ static void OPC_6502_90 (void)
static void OPC_6502_91 (void)
/* Opcode $91: sta (zp),y */
{
- unsigned char ZPAddr;
- unsigned Addr;
- Cycles = 6;
- ZPAddr = MemReadByte (Regs.PC+1);
- Addr = MemReadZPWord (ZPAddr) + Regs.YR;
- MemWriteByte (Addr, Regs.AC);
- Regs.PC += 2;
+ STO_OP (ZPINDY, Regs.AC);
}
@@ -1627,13 +2333,15 @@ static void OPC_6502_91 (void)
static void OPC_65SC02_92 (void)
/* Opcode $92: sta (zp) */
{
- unsigned char ZPAddr;
- unsigned Addr;
- Cycles = 5;
- ZPAddr = MemReadByte (Regs.PC+1);
- Addr = MemReadZPWord (ZPAddr);
- MemWriteByte (Addr, Regs.AC);
- Regs.PC += 2;
+ STO_OP (ZPIND, Regs.AC);
+}
+
+
+
+static void OPC_6502_93 (void)
+/* Opcode $93: SHA (zp),y */
+{
+ STO_CB (ZPINDY, SHA);
}
@@ -1641,11 +2349,7 @@ static void OPC_65SC02_92 (void)
static void OPC_6502_94 (void)
/* Opcode $94: STY zp,x */
{
- unsigned char ZPAddr;
- Cycles = 4;
- ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
- MemWriteByte (ZPAddr, Regs.YR);
- Regs.PC += 2;
+ STO_OP (ZPX, Regs.YR);
}
@@ -1653,11 +2357,7 @@ static void OPC_6502_94 (void)
static void OPC_6502_95 (void)
/* Opcode $95: STA zp,x */
{
- unsigned char ZPAddr;
- Cycles = 4;
- ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
- MemWriteByte (ZPAddr, Regs.AC);
- Regs.PC += 2;
+ STO_OP (ZPX, Regs.AC);
}
@@ -1665,11 +2365,15 @@ static void OPC_6502_95 (void)
static void OPC_6502_96 (void)
/* Opcode $96: stx zp,y */
{
- unsigned char ZPAddr;
- Cycles = 4;
- ZPAddr = MemReadByte (Regs.PC+1) + Regs.YR;
- MemWriteByte (ZPAddr, Regs.XR);
- Regs.PC += 2;
+ STO_OP (ZPY, Regs.XR);
+}
+
+
+
+static void OPC_6502_97 (void)
+/* Opcode $97: SAX zp,y */
+{
+ STO_OP (ZPY, Regs.AC & Regs.XR);
}
@@ -1689,11 +2393,7 @@ static void OPC_6502_98 (void)
static void OPC_6502_99 (void)
/* Opcode $99: STA abs,y */
{
- unsigned Addr;
- Cycles = 5;
- Addr = MemReadWord (Regs.PC+1) + Regs.YR;
- MemWriteByte (Addr, Regs.AC);
- Regs.PC += 3;
+ STO_OP (ABSY, Regs.AC);
}
@@ -1708,14 +2408,26 @@ static void OPC_6502_9A (void)
+static void OPC_6502_9B (void)
+/* Opcode $9B: TAS abs,y */
+{
+ STO_CB (ABSY, TAS);
+}
+
+
+
+static void OPC_6502_9C (void)
+/* Opcode $9D: SHY abs,x */
+{
+ STO_OP (ABSX, Regs.YR & ((address >> 8) + 1));
+}
+
+
+
static void OPC_65SC02_9C (void)
/* Opcode $9C: STZ abs */
{
- unsigned Addr;
- Cycles = 4;
- Addr = MemReadWord (Regs.PC+1);
- MemWriteByte (Addr, 0);
- Regs.PC += 3;
+ STO_OP (ABS, 0);
}
@@ -1723,11 +2435,23 @@ static void OPC_65SC02_9C (void)
static void OPC_6502_9D (void)
/* Opcode $9D: STA abs,x */
{
- unsigned Addr;
- Cycles = 5;
- Addr = MemReadWord (Regs.PC+1) + Regs.XR;
- MemWriteByte (Addr, Regs.AC);
- Regs.PC += 3;
+ STO_OP (ABSX, Regs.AC);
+}
+
+
+
+static void OPC_6502_9E (void)
+/* Opcode $9E: SHX abs,x */
+{
+ STO_OP (ABSY, Regs.XR & ((address >> 8) + 1));
+}
+
+
+
+static void OPC_6502_9F (void)
+/* Opcode $9F: SHA abs,y */
+{
+ STO_CB (ABSY, SHA);
}
@@ -1735,11 +2459,7 @@ static void OPC_6502_9D (void)
static void OPC_65SC02_9E (void)
/* Opcode $9E: STZ abs,x */
{
- unsigned Addr;
- Cycles = 5;
- Addr = MemReadWord (Regs.PC+1) + Regs.XR;
- MemWriteByte (Addr, 0);
- Regs.PC += 3;
+ STO_OP (ABSX, 0);
}
@@ -1747,11 +2467,7 @@ static void OPC_65SC02_9E (void)
static void OPC_6502_A0 (void)
/* Opcode $A0: LDY #imm */
{
- Cycles = 2;
- Regs.YR = MemReadByte (Regs.PC+1);
- TEST_ZF (Regs.YR);
- TEST_SF (Regs.YR);
- Regs.PC += 2;
+ ALU_OP_IMM (LDY);
}
@@ -1759,15 +2475,7 @@ static void OPC_6502_A0 (void)
static void OPC_6502_A1 (void)
/* Opcode $A1: LDA (zp,x) */
{
- unsigned char ZPAddr;
- unsigned Addr;
- Cycles = 6;
- ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
- Addr = MemReadZPWord (ZPAddr);
- Regs.AC = MemReadByte (Addr);
- TEST_ZF (Regs.AC);
- TEST_SF (Regs.AC);
- Regs.PC += 2;
+ ALU_OP (ZPXIND, LDA);
}
@@ -1775,11 +2483,15 @@ static void OPC_6502_A1 (void)
static void OPC_6502_A2 (void)
/* Opcode $A2: LDX #imm */
{
- Cycles = 2;
- Regs.XR = MemReadByte (Regs.PC+1);
- TEST_ZF (Regs.XR);
- TEST_SF (Regs.XR);
- Regs.PC += 2;
+ ALU_OP_IMM (LDX);
+}
+
+
+
+static void OPC_6502_A3 (void)
+/* Opcode $A3: LAX (zp,x) */
+{
+ ALU_OP (ZPXIND, LAX);
}
@@ -1787,13 +2499,7 @@ static void OPC_6502_A2 (void)
static void OPC_6502_A4 (void)
/* Opcode $A4: LDY zp */
{
- unsigned char ZPAddr;
- Cycles = 3;
- ZPAddr = MemReadByte (Regs.PC+1);
- Regs.YR = MemReadByte (ZPAddr);
- TEST_ZF (Regs.YR);
- TEST_SF (Regs.YR);
- Regs.PC += 2;
+ ALU_OP (ZP, LDY);
}
@@ -1801,13 +2507,7 @@ static void OPC_6502_A4 (void)
static void OPC_6502_A5 (void)
/* Opcode $A5: LDA zp */
{
- unsigned char ZPAddr;
- Cycles = 3;
- ZPAddr = MemReadByte (Regs.PC+1);
- Regs.AC = MemReadByte (ZPAddr);
- TEST_ZF (Regs.AC);
- TEST_SF (Regs.AC);
- Regs.PC += 2;
+ ALU_OP (ZP, LDA);
}
@@ -1815,13 +2515,15 @@ static void OPC_6502_A5 (void)
static void OPC_6502_A6 (void)
/* Opcode $A6: LDX zp */
{
- unsigned char ZPAddr;
- Cycles = 3;
- ZPAddr = MemReadByte (Regs.PC+1);
- Regs.XR = MemReadByte (ZPAddr);
- TEST_ZF (Regs.XR);
- TEST_SF (Regs.XR);
- Regs.PC += 2;
+ ALU_OP (ZP, LDX);
+}
+
+
+
+static void OPC_6502_A7 (void)
+/* Opcode $A7: LAX zp */
+{
+ ALU_OP (ZP, LAX);
}
@@ -1841,11 +2543,7 @@ static void OPC_6502_A8 (void)
static void OPC_6502_A9 (void)
/* Opcode $A9: LDA #imm */
{
- Cycles = 2;
- Regs.AC = MemReadByte (Regs.PC+1);
- TEST_ZF (Regs.AC);
- TEST_SF (Regs.AC);
- Regs.PC += 2;
+ ALU_OP_IMM (LDA);
}
@@ -1862,16 +2560,18 @@ static void OPC_6502_AA (void)
+static void OPC_6502_AB (void)
+/* Opcode $AB: LXA imm */
+{
+ ALU_OP_IMM (LXA);
+}
+
+
+
static void OPC_6502_AC (void)
/* Opcode $Regs.AC: LDY abs */
{
- unsigned Addr;
- Cycles = 4;
- Addr = MemReadWord (Regs.PC+1);
- Regs.YR = MemReadByte (Addr);
- TEST_ZF (Regs.YR);
- TEST_SF (Regs.YR);
- Regs.PC += 3;
+ ALU_OP (ABS, LDY);
}
@@ -1879,13 +2579,7 @@ static void OPC_6502_AC (void)
static void OPC_6502_AD (void)
/* Opcode $AD: LDA abs */
{
- unsigned Addr;
- Cycles = 4;
- Addr = MemReadWord (Regs.PC+1);
- Regs.AC = MemReadByte (Addr);
- TEST_ZF (Regs.AC);
- TEST_SF (Regs.AC);
- Regs.PC += 3;
+ ALU_OP (ABS, LDA);
}
@@ -1893,13 +2587,15 @@ static void OPC_6502_AD (void)
static void OPC_6502_AE (void)
/* Opcode $AE: LDX abs */
{
- unsigned Addr;
- Cycles = 4;
- Addr = MemReadWord (Regs.PC+1);
- Regs.XR = MemReadByte (Addr);
- TEST_ZF (Regs.XR);
- TEST_SF (Regs.XR);
- Regs.PC += 3;
+ ALU_OP (ABS, LDX);
+}
+
+
+
+static void OPC_6502_AF (void)
+/* Opcode $AF: LAX abs */
+{
+ ALU_OP (ABS, LAX);
}
@@ -1915,18 +2611,7 @@ static void OPC_6502_B0 (void)
static void OPC_6502_B1 (void)
/* Opcode $B1: LDA (zp),y */
{
- unsigned char ZPAddr;
- unsigned Addr;
- Cycles = 5;
- ZPAddr = MemReadByte (Regs.PC+1);
- Addr = MemReadZPWord (ZPAddr);
- if (PAGE_CROSS (Addr, Regs.YR)) {
- ++Cycles;
- }
- Regs.AC = MemReadByte (Addr + Regs.YR);
- TEST_ZF (Regs.AC);
- TEST_SF (Regs.AC);
- Regs.PC += 2;
+ ALU_OP (ZPINDY, LDA);
}
@@ -1934,15 +2619,15 @@ static void OPC_6502_B1 (void)
static void OPC_65SC02_B2 (void)
/* Opcode $B2: LDA (zp) */
{
- unsigned char ZPAddr;
- unsigned Addr;
- Cycles = 5;
- ZPAddr = MemReadByte (Regs.PC+1);
- Addr = MemReadZPWord (ZPAddr);
- Regs.AC = MemReadByte (Addr);
- TEST_ZF (Regs.AC);
- TEST_SF (Regs.AC);
- Regs.PC += 2;
+ ALU_OP (ZPIND, LDA);
+}
+
+
+
+static void OPC_6502_B3 (void)
+/* Opcode $B3: LAX (zp),y */
+{
+ ALU_OP (ZPINDY, LAX);
}
@@ -1950,13 +2635,7 @@ static void OPC_65SC02_B2 (void)
static void OPC_6502_B4 (void)
/* Opcode $B4: LDY zp,x */
{
- unsigned char ZPAddr;
- Cycles = 4;
- ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
- Regs.YR = MemReadByte (ZPAddr);
- TEST_ZF (Regs.YR);
- TEST_SF (Regs.YR);
- Regs.PC += 2;
+ ALU_OP (ZPX, LDY);
}
@@ -1964,13 +2643,7 @@ static void OPC_6502_B4 (void)
static void OPC_6502_B5 (void)
/* Opcode $B5: LDA zp,x */
{
- unsigned char ZPAddr;
- Cycles = 4;
- ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
- Regs.AC = MemReadByte (ZPAddr);
- TEST_ZF (Regs.AC);
- TEST_SF (Regs.AC);
- Regs.PC += 2;
+ ALU_OP (ZPX, LDA);
}
@@ -1978,13 +2651,15 @@ static void OPC_6502_B5 (void)
static void OPC_6502_B6 (void)
/* Opcode $B6: LDX zp,y */
{
- unsigned char ZPAddr;
- Cycles = 4;
- ZPAddr = MemReadByte (Regs.PC+1) + Regs.YR;
- Regs.XR = MemReadByte (ZPAddr);
- TEST_ZF (Regs.XR);
- TEST_SF (Regs.XR);
- Regs.PC += 2;
+ ALU_OP (ZPY, LDX);
+}
+
+
+
+static void OPC_6502_B7 (void)
+/* Opcode $B7: LAX zp,y */
+{
+ ALU_OP (ZPY, LAX);
}
@@ -2002,16 +2677,7 @@ static void OPC_6502_B8 (void)
static void OPC_6502_B9 (void)
/* Opcode $B9: LDA abs,y */
{
- unsigned Addr;
- Cycles = 4;
- Addr = MemReadWord (Regs.PC+1);
- if (PAGE_CROSS (Addr, Regs.YR)) {
- ++Cycles;
- }
- Regs.AC = MemReadByte (Addr + Regs.YR);
- TEST_ZF (Regs.AC);
- TEST_SF (Regs.AC);
- Regs.PC += 3;
+ ALU_OP (ABSY, LDA);
}
@@ -2028,19 +2694,18 @@ static void OPC_6502_BA (void)
+static void OPC_6502_BB (void)
+/* Opcode $BB: LAS abs,y */
+{
+ ALU_OP (ABSY, LAS);
+}
+
+
+
static void OPC_6502_BC (void)
/* Opcode $BC: LDY abs,x */
{
- unsigned Addr;
- Cycles = 4;
- Addr = MemReadWord (Regs.PC+1);
- if (PAGE_CROSS (Addr, Regs.XR)) {
- ++Cycles;
- }
- Regs.YR = MemReadByte (Addr + Regs.XR);
- TEST_ZF (Regs.YR);
- TEST_SF (Regs.YR);
- Regs.PC += 3;
+ ALU_OP (ABSX, LDY);
}
@@ -2048,16 +2713,7 @@ static void OPC_6502_BC (void)
static void OPC_6502_BD (void)
/* Opcode $BD: LDA abs,x */
{
- unsigned Addr;
- Cycles = 4;
- Addr = MemReadWord (Regs.PC+1);
- if (PAGE_CROSS (Addr, Regs.XR)) {
- ++Cycles;
- }
- Regs.AC = MemReadByte (Addr + Regs.XR);
- TEST_ZF (Regs.AC);
- TEST_SF (Regs.AC);
- Regs.PC += 3;
+ ALU_OP (ABSX, LDA);
}
@@ -2065,16 +2721,15 @@ static void OPC_6502_BD (void)
static void OPC_6502_BE (void)
/* Opcode $BE: LDX abs,y */
{
- unsigned Addr;
- Cycles = 4;
- Addr = MemReadWord (Regs.PC+1);
- if (PAGE_CROSS (Addr, Regs.YR)) {
- ++Cycles;
- }
- Regs.XR = MemReadByte (Addr + Regs.YR);
- TEST_ZF (Regs.XR);
- TEST_SF (Regs.XR);
- Regs.PC += 3;
+ ALU_OP (ABSY, LDX);
+}
+
+
+
+static void OPC_6502_BF (void)
+/* Opcode $BF: LAX abs,y */
+{
+ ALU_OP (ABSY, LAX);
}
@@ -2082,9 +2737,7 @@ static void OPC_6502_BE (void)
static void OPC_6502_C0 (void)
/* Opcode $C0: CPY #imm */
{
- Cycles = 2;
- CMP (Regs.YR, MemReadByte (Regs.PC+1));
- Regs.PC += 2;
+ ALU_OP_IMM (CPY);
}
@@ -2092,13 +2745,15 @@ static void OPC_6502_C0 (void)
static void OPC_6502_C1 (void)
/* Opcode $C1: CMP (zp,x) */
{
- unsigned char ZPAddr;
- unsigned Addr;
- Cycles = 6;
- ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
- Addr = MemReadZPWord (ZPAddr);
- CMP (Regs.AC, MemReadByte (Addr));
- Regs.PC += 2;
+ ALU_OP (ZPXIND, CMP);
+}
+
+
+
+static void OPC_6502_C3 (void)
+/* Opcode $C3: DCP (zp,x) */
+{
+ MEM_OP (ZPXIND, DCP);
}
@@ -2106,11 +2761,7 @@ static void OPC_6502_C1 (void)
static void OPC_6502_C4 (void)
/* Opcode $C4: CPY zp */
{
- unsigned char ZPAddr;
- Cycles = 3;
- ZPAddr = MemReadByte (Regs.PC+1);
- CMP (Regs.YR, MemReadByte (ZPAddr));
- Regs.PC += 2;
+ ALU_OP (ZP, CPY);
}
@@ -2118,11 +2769,7 @@ static void OPC_6502_C4 (void)
static void OPC_6502_C5 (void)
/* Opcode $C5: CMP zp */
{
- unsigned char ZPAddr;
- Cycles = 3;
- ZPAddr = MemReadByte (Regs.PC+1);
- CMP (Regs.AC, MemReadByte (ZPAddr));
- Regs.PC += 2;
+ ALU_OP (ZP, CMP);
}
@@ -2130,15 +2777,15 @@ static void OPC_6502_C5 (void)
static void OPC_6502_C6 (void)
/* Opcode $C6: DEC zp */
{
- unsigned char ZPAddr;
- unsigned char Val;
- Cycles = 5;
- ZPAddr = MemReadByte (Regs.PC+1);
- Val = MemReadByte (ZPAddr) - 1;
- MemWriteByte (ZPAddr, Val);
- TEST_ZF (Val);
- TEST_SF (Val);
- Regs.PC += 2;
+ MEM_OP (ZP, DEC);
+}
+
+
+
+static void OPC_6502_C7 (void)
+/* Opcode $C7: DCP zp */
+{
+ MEM_OP (ZP, DCP);
}
@@ -2147,9 +2794,7 @@ static void OPC_6502_C8 (void)
/* Opcode $C8: INY */
{
Cycles = 2;
- Regs.YR = (Regs.YR + 1) & 0xFF;
- TEST_ZF (Regs.YR);
- TEST_SF (Regs.YR);
+ INC(Regs.YR);
Regs.PC += 1;
}
@@ -2158,9 +2803,7 @@ static void OPC_6502_C8 (void)
static void OPC_6502_C9 (void)
/* Opcode $C9: CMP #imm */
{
- Cycles = 2;
- CMP (Regs.AC, MemReadByte (Regs.PC+1));
- Regs.PC += 2;
+ ALU_OP_IMM (CMP);
}
@@ -2169,22 +2812,24 @@ static void OPC_6502_CA (void)
/* Opcode $CA: DEX */
{
Cycles = 2;
- Regs.XR = (Regs.XR - 1) & 0xFF;
- TEST_ZF (Regs.XR);
- TEST_SF (Regs.XR);
+ DEC (Regs.XR);
Regs.PC += 1;
}
+static void OPC_6502_CB (void)
+/* Opcode $CB: SBX imm */
+{
+ ALU_OP_IMM (SBX);
+}
+
+
+
static void OPC_6502_CC (void)
/* Opcode $CC: CPY abs */
{
- unsigned Addr;
- Cycles = 4;
- Addr = MemReadWord (Regs.PC+1);
- CMP (Regs.YR, MemReadByte (Addr));
- Regs.PC += 3;
+ ALU_OP (ABS, CPY);
}
@@ -2192,11 +2837,7 @@ static void OPC_6502_CC (void)
static void OPC_6502_CD (void)
/* Opcode $CD: CMP abs */
{
- unsigned Addr;
- Cycles = 4;
- Addr = MemReadWord (Regs.PC+1);
- CMP (Regs.AC, MemReadByte (Addr));
- Regs.PC += 3;
+ ALU_OP (ABS, CMP);
}
@@ -2204,15 +2845,15 @@ static void OPC_6502_CD (void)
static void OPC_6502_CE (void)
/* Opcode $CE: DEC abs */
{
- unsigned Addr;
- unsigned char Val;
- Cycles = 6;
- Addr = MemReadWord (Regs.PC+1);
- Val = MemReadByte (Addr) - 1;
- MemWriteByte (Addr, Val);
- TEST_ZF (Val);
- TEST_SF (Val);
- Regs.PC += 3;
+ MEM_OP (ABS, DEC);
+}
+
+
+
+static void OPC_6502_CF (void)
+/* Opcode $CF: DCP abs */
+{
+ MEM_OP (ABS, DCP);
}
@@ -2228,16 +2869,7 @@ static void OPC_6502_D0 (void)
static void OPC_6502_D1 (void)
/* Opcode $D1: CMP (zp),y */
{
- unsigned ZPAddr;
- unsigned Addr;
- Cycles = 5;
- ZPAddr = MemReadByte (Regs.PC+1);
- Addr = MemReadWord (ZPAddr);
- if (PAGE_CROSS (Addr, Regs.YR)) {
- ++Cycles;
- }
- CMP (Regs.AC, MemReadByte (Addr + Regs.YR));
- Regs.PC += 2;
+ ALU_OP (ZPINDY, CMP);
}
@@ -2245,13 +2877,15 @@ static void OPC_6502_D1 (void)
static void OPC_65SC02_D2 (void)
/* Opcode $D2: CMP (zp) */
{
- unsigned ZPAddr;
- unsigned Addr;
- Cycles = 5;
- ZPAddr = MemReadByte (Regs.PC+1);
- Addr = MemReadWord (ZPAddr);
- CMP (Regs.AC, MemReadByte (Addr));
- Regs.PC += 2;
+ ALU_OP (ZPIND, CMP);
+}
+
+
+
+static void OPC_6502_D3 (void)
+/* Opcode $D3: DCP (zp),y */
+{
+ MEM_OP (ZPINDY, DCP);
}
@@ -2259,11 +2893,7 @@ static void OPC_65SC02_D2 (void)
static void OPC_6502_D5 (void)
/* Opcode $D5: CMP zp,x */
{
- unsigned char ZPAddr;
- Cycles = 4;
- ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
- CMP (Regs.AC, MemReadByte (ZPAddr));
- Regs.PC += 2;
+ ALU_OP (ZPX, CMP);
}
@@ -2271,15 +2901,15 @@ static void OPC_6502_D5 (void)
static void OPC_6502_D6 (void)
/* Opcode $D6: DEC zp,x */
{
- unsigned char ZPAddr;
- unsigned char Val;
- Cycles = 6;
- ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
- Val = MemReadByte (ZPAddr) - 1;
- MemWriteByte (ZPAddr, Val);
- TEST_ZF (Val);
- TEST_SF (Val);
- Regs.PC += 2;
+ MEM_OP (ZPX, DEC);
+}
+
+
+
+static void OPC_6502_D7 (void)
+/* Opcode $D7: DCP zp,x */
+{
+ MEM_OP (ZPX, DCP);
}
@@ -2297,14 +2927,7 @@ static void OPC_6502_D8 (void)
static void OPC_6502_D9 (void)
/* Opcode $D9: CMP abs,y */
{
- unsigned Addr;
- Cycles = 4;
- Addr = MemReadWord (Regs.PC+1);
- if (PAGE_CROSS (Addr, Regs.YR)) {
- ++Cycles;
- }
- CMP (Regs.AC, MemReadByte (Addr + Regs.YR));
- Regs.PC += 3;
+ ALU_OP (ABSY, CMP);
}
@@ -2319,17 +2942,18 @@ static void OPC_65SC02_DA (void)
+static void OPC_6502_DB (void)
+/* Opcode $DB: DCP abs,y */
+{
+ MEM_OP (ABSY, DCP);
+}
+
+
+
static void OPC_6502_DD (void)
/* Opcode $DD: CMP abs,x */
{
- unsigned Addr;
- Cycles = 4;
- Addr = MemReadWord (Regs.PC+1);
- if (PAGE_CROSS (Addr, Regs.XR)) {
- ++Cycles;
- }
- CMP (Regs.AC, MemReadByte (Addr + Regs.XR));
- Regs.PC += 3;
+ ALU_OP (ABSX, CMP);
}
@@ -2337,15 +2961,15 @@ static void OPC_6502_DD (void)
static void OPC_6502_DE (void)
/* Opcode $DE: DEC abs,x */
{
- unsigned Addr;
- unsigned char Val;
- Cycles = 7;
- Addr = MemReadWord (Regs.PC+1) + Regs.XR;
- Val = MemReadByte (Addr) - 1;
- MemWriteByte (Addr, Val);
- TEST_ZF (Val);
- TEST_SF (Val);
- Regs.PC += 3;
+ MEM_OP (ABSX, DEC);
+}
+
+
+
+static void OPC_6502_DF (void)
+/* Opcode $DF: DCP abs,x */
+{
+ MEM_OP (ABSX, DCP);
}
@@ -2353,9 +2977,7 @@ static void OPC_6502_DE (void)
static void OPC_6502_E0 (void)
/* Opcode $E0: CPX #imm */
{
- Cycles = 2;
- CMP (Regs.XR, MemReadByte (Regs.PC+1));
- Regs.PC += 2;
+ ALU_OP_IMM (CPX);
}
@@ -2363,13 +2985,15 @@ static void OPC_6502_E0 (void)
static void OPC_6502_E1 (void)
/* Opcode $E1: SBC (zp,x) */
{
- unsigned char ZPAddr;
- unsigned Addr;
- Cycles = 6;
- ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
- Addr = MemReadZPWord (ZPAddr);
- SBC (MemReadByte (Addr));
- Regs.PC += 2;
+ ALU_OP (ZPXIND, SBC);
+}
+
+
+
+static void OPC_6502_E3 (void)
+/* Opcode $E3: ISC (zp,x) */
+{
+ MEM_OP (ZPXIND, ISC);
}
@@ -2377,11 +3001,7 @@ static void OPC_6502_E1 (void)
static void OPC_6502_E4 (void)
/* Opcode $E4: CPX zp */
{
- unsigned char ZPAddr;
- Cycles = 3;
- ZPAddr = MemReadByte (Regs.PC+1);
- CMP (Regs.XR, MemReadByte (ZPAddr));
- Regs.PC += 2;
+ ALU_OP (ZP, CPX);
}
@@ -2389,11 +3009,7 @@ static void OPC_6502_E4 (void)
static void OPC_6502_E5 (void)
/* Opcode $E5: SBC zp */
{
- unsigned char ZPAddr;
- Cycles = 3;
- ZPAddr = MemReadByte (Regs.PC+1);
- SBC (MemReadByte (ZPAddr));
- Regs.PC += 2;
+ ALU_OP (ZP, SBC);
}
@@ -2401,15 +3017,15 @@ static void OPC_6502_E5 (void)
static void OPC_6502_E6 (void)
/* Opcode $E6: INC zp */
{
- unsigned char ZPAddr;
- unsigned char Val;
- Cycles = 5;
- ZPAddr = MemReadByte (Regs.PC+1);
- Val = MemReadByte (ZPAddr) + 1;
- MemWriteByte (ZPAddr, Val);
- TEST_ZF (Val);
- TEST_SF (Val);
- Regs.PC += 2;
+ MEM_OP (ZP, INC);
+}
+
+
+
+static void OPC_6502_E7 (void)
+/* Opcode $E7: ISC zp */
+{
+ MEM_OP (ZP, ISC);
}
@@ -2418,24 +3034,31 @@ static void OPC_6502_E8 (void)
/* Opcode $E8: INX */
{
Cycles = 2;
- Regs.XR = (Regs.XR + 1) & 0xFF;
- TEST_ZF (Regs.XR);
- TEST_SF (Regs.XR);
+ INC (Regs.XR);
Regs.PC += 1;
}
+/* Aliases of opcode $EA */
+#define OPC_6502_EB OPC_6502_E9
+
static void OPC_6502_E9 (void)
/* Opcode $E9: SBC #imm */
{
- Cycles = 2;
- SBC (MemReadByte (Regs.PC+1));
- Regs.PC += 2;
+ ALU_OP_IMM (SBC);
}
+/* Aliases of opcode $EA */
+#define OPC_6502_1A OPC_6502_EA
+#define OPC_6502_3A OPC_6502_EA
+#define OPC_6502_5A OPC_6502_EA
+#define OPC_6502_7A OPC_6502_EA
+#define OPC_6502_DA OPC_6502_EA
+#define OPC_6502_FA OPC_6502_EA
+
static void OPC_6502_EA (void)
/* Opcode $EA: NOP */
{
@@ -2485,11 +3108,7 @@ static void OPC_65C02_NOP34 (void)
static void OPC_6502_EC (void)
/* Opcode $EC: CPX abs */
{
- unsigned Addr;
- Cycles = 4;
- Addr = MemReadWord (Regs.PC+1);
- CMP (Regs.XR, MemReadByte (Addr));
- Regs.PC += 3;
+ ALU_OP (ABS, CPX);
}
@@ -2497,27 +3116,22 @@ static void OPC_6502_EC (void)
static void OPC_6502_ED (void)
/* Opcode $ED: SBC abs */
{
- unsigned Addr;
- Cycles = 4;
- Addr = MemReadWord (Regs.PC+1);
- SBC (MemReadByte (Addr));
- Regs.PC += 3;
+ ALU_OP (ABS, SBC);
}
-
static void OPC_6502_EE (void)
/* Opcode $EE: INC abs */
{
- unsigned Addr;
- unsigned char Val;
- Cycles = 6;
- Addr = MemReadWord (Regs.PC+1);
- Val = MemReadByte (Addr) + 1;
- MemWriteByte (Addr, Val);
- TEST_ZF (Val);
- TEST_SF (Val);
- Regs.PC += 3;
+ MEM_OP (ABS, INC);
+}
+
+
+
+static void OPC_6502_EF (void)
+/* Opcode $EF: ISC abs */
+{
+ MEM_OP (ABS, ISC);
}
@@ -2533,16 +3147,7 @@ static void OPC_6502_F0 (void)
static void OPC_6502_F1 (void)
/* Opcode $F1: SBC (zp),y */
{
- unsigned char ZPAddr;
- unsigned Addr;
- Cycles = 5;
- ZPAddr = MemReadByte (Regs.PC+1);
- Addr = MemReadZPWord (ZPAddr);
- if (PAGE_CROSS (Addr, Regs.YR)) {
- ++Cycles;
- }
- SBC (MemReadByte (Addr + Regs.YR));
- Regs.PC += 2;
+ ALU_OP (ZPINDY, SBC);
}
@@ -2550,13 +3155,15 @@ static void OPC_6502_F1 (void)
static void OPC_65SC02_F2 (void)
/* Opcode $F2: SBC (zp) */
{
- unsigned char ZPAddr;
- unsigned Addr;
- Cycles = 5;
- ZPAddr = MemReadByte (Regs.PC+1);
- Addr = MemReadZPWord (ZPAddr);
- SBC (MemReadByte (Addr));
- Regs.PC += 2;
+ ALU_OP (ZPIND, SBC);
+}
+
+
+
+static void OPC_6502_F3 (void)
+/* Opcode $F3: ISC (zp),y */
+{
+ MEM_OP (ZPINDY, ISC);
}
@@ -2564,11 +3171,7 @@ static void OPC_65SC02_F2 (void)
static void OPC_6502_F5 (void)
/* Opcode $F5: SBC zp,x */
{
- unsigned char ZPAddr;
- Cycles = 4;
- ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
- SBC (MemReadByte (ZPAddr));
- Regs.PC += 2;
+ ALU_OP (ZPX, SBC);
}
@@ -2576,15 +3179,15 @@ static void OPC_6502_F5 (void)
static void OPC_6502_F6 (void)
/* Opcode $F6: INC zp,x */
{
- unsigned char ZPAddr;
- unsigned char Val;
- Cycles = 6;
- ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
- Val = MemReadByte (ZPAddr) + 1;
- MemWriteByte (ZPAddr, Val);
- TEST_ZF (Val);
- TEST_SF (Val);
- Regs.PC += 2;
+ MEM_OP (ZPX, INC);
+}
+
+
+
+static void OPC_6502_F7 (void)
+/* Opcode $F7: ISC zp,x */
+{
+ MEM_OP (ZPX, ISC);
}
@@ -2602,14 +3205,7 @@ static void OPC_6502_F8 (void)
static void OPC_6502_F9 (void)
/* Opcode $F9: SBC abs,y */
{
- unsigned Addr;
- Cycles = 4;
- Addr = MemReadWord (Regs.PC+1);
- if (PAGE_CROSS (Addr, Regs.YR)) {
- ++Cycles;
- }
- SBC (MemReadByte (Addr + Regs.YR));
- Regs.PC += 3;
+ ALU_OP (ABSY, SBC);
}
@@ -2626,17 +3222,18 @@ static void OPC_65SC02_FA (void)
+static void OPC_6502_FB (void)
+/* Opcode $FB: ISC abs,y */
+{
+ MEM_OP (ABSY, ISC);
+}
+
+
+
static void OPC_6502_FD (void)
/* Opcode $FD: SBC abs,x */
{
- unsigned Addr;
- Cycles = 4;
- Addr = MemReadWord (Regs.PC+1);
- if (PAGE_CROSS (Addr, Regs.XR)) {
- ++Cycles;
- }
- SBC (MemReadByte (Addr + Regs.XR));
- Regs.PC += 3;
+ ALU_OP (ABSX, SBC);
}
@@ -2644,15 +3241,15 @@ static void OPC_6502_FD (void)
static void OPC_6502_FE (void)
/* Opcode $FE: INC abs,x */
{
- unsigned Addr;
- unsigned char Val;
- Cycles = 7;
- Addr = MemReadWord (Regs.PC+1) + Regs.XR;
- Val = MemReadByte (Addr) + 1;
- MemWriteByte (Addr, Val);
- TEST_ZF (Val);
- TEST_SF (Val);
- Regs.PC += 3;
+ MEM_OP (ABSX, INC);
+}
+
+
+
+static void OPC_6502_FF (void)
+/* Opcode $FF: ISC abs,x */
+{
+ MEM_OP (ABSX, ISC);
}
@@ -2925,6 +3522,268 @@ static const OPFunc OP6502Table[256] = {
+/* Opcode handler table for the 6502X */
+static const OPFunc OP6502XTable[256] = {
+ OPC_6502_00,
+ OPC_6502_01,
+ OPC_Illegal,
+ OPC_6502_03,
+ OPC_6502_04,
+ OPC_6502_05,
+ OPC_6502_06,
+ OPC_6502_07,
+ OPC_6502_08,
+ OPC_6502_09,
+ OPC_6502_0A,
+ OPC_6502_0B,
+ OPC_6502_0C,
+ OPC_6502_0D,
+ OPC_6502_0E,
+ OPC_6502_0F,
+ OPC_6502_10,
+ OPC_6502_11,
+ OPC_Illegal,
+ OPC_6502_13,
+ OPC_6502_14,
+ OPC_6502_15,
+ OPC_6502_16,
+ OPC_6502_17,
+ OPC_6502_18,
+ OPC_6502_19,
+ OPC_6502_1A,
+ OPC_6502_1B,
+ OPC_6502_1C,
+ OPC_6502_1D,
+ OPC_6502_1E,
+ OPC_6502_1F,
+ OPC_6502_20,
+ OPC_6502_21,
+ OPC_Illegal,
+ OPC_6502_23,
+ OPC_6502_24,
+ OPC_6502_25,
+ OPC_6502_26,
+ OPC_6502_27,
+ OPC_6502_28,
+ OPC_6502_29,
+ OPC_6502_2A,
+ OPC_6502_2B,
+ OPC_6502_2C,
+ OPC_6502_2D,
+ OPC_6502_2E,
+ OPC_6502_2F,
+ OPC_6502_30,
+ OPC_6502_31,
+ OPC_Illegal,
+ OPC_6502_33,
+ OPC_6502_34,
+ OPC_6502_35,
+ OPC_6502_36,
+ OPC_6502_37,
+ OPC_6502_38,
+ OPC_6502_39,
+ OPC_6502_3A,
+ OPC_6502_3B,
+ OPC_6502_3C,
+ OPC_6502_3D,
+ OPC_6502_3E,
+ OPC_6502_3F,
+ OPC_6502_40,
+ OPC_6502_41,
+ OPC_Illegal,
+ OPC_6502_43,
+ OPC_6502_44,
+ OPC_6502_45,
+ OPC_6502_46,
+ OPC_6502_47,
+ OPC_6502_48,
+ OPC_6502_49,
+ OPC_6502_4A,
+ OPC_6502_4B,
+ OPC_6502_4C,
+ OPC_6502_4D,
+ OPC_6502_4E,
+ OPC_6502_4F,
+ OPC_6502_50,
+ OPC_6502_51,
+ OPC_Illegal,
+ OPC_6502_53,
+ OPC_6502_54,
+ OPC_6502_55,
+ OPC_6502_56,
+ OPC_6502_57,
+ OPC_6502_58,
+ OPC_6502_59,
+ OPC_6502_5A,
+ OPC_6502_5B,
+ OPC_6502_5C,
+ OPC_6502_5D,
+ OPC_6502_5E,
+ OPC_6502_5F,
+ OPC_6502_60,
+ OPC_6502_61,
+ OPC_Illegal,
+ OPC_6502_63,
+ OPC_6502_64,
+ OPC_6502_65,
+ OPC_6502_66,
+ OPC_6502_67,
+ OPC_6502_68,
+ OPC_6502_69,
+ OPC_6502_6A,
+ OPC_6502_6B,
+ OPC_6502_6C,
+ OPC_6502_6D,
+ OPC_6502_6E,
+ OPC_6502_6F,
+ OPC_6502_70,
+ OPC_6502_71,
+ OPC_Illegal,
+ OPC_6502_73,
+ OPC_6502_74,
+ OPC_6502_75,
+ OPC_6502_76,
+ OPC_6502_77,
+ OPC_6502_78,
+ OPC_6502_79,
+ OPC_6502_7A,
+ OPC_6502_7B,
+ OPC_6502_7C,
+ OPC_6502_7D,
+ OPC_6502_7E,
+ OPC_6502_7F,
+ OPC_6502_80,
+ OPC_6502_81,
+ OPC_6502_82,
+ OPC_6502_83,
+ OPC_6502_84,
+ OPC_6502_85,
+ OPC_6502_86,
+ OPC_6502_87,
+ OPC_6502_88,
+ OPC_6502_89,
+ OPC_6502_8A,
+ OPC_6502_8B,
+ OPC_6502_8C,
+ OPC_6502_8D,
+ OPC_6502_8E,
+ OPC_6502_8F,
+ OPC_6502_90,
+ OPC_6502_91,
+ OPC_Illegal,
+ OPC_6502_93,
+ OPC_6502_94,
+ OPC_6502_95,
+ OPC_6502_96,
+ OPC_6502_97,
+ OPC_6502_98,
+ OPC_6502_99,
+ OPC_6502_9A,
+ OPC_6502_9B,
+ OPC_6502_9C,
+ OPC_6502_9D,
+ OPC_6502_9E,
+ OPC_6502_9F,
+ OPC_6502_A0,
+ OPC_6502_A1,
+ OPC_6502_A2,
+ OPC_6502_A3,
+ OPC_6502_A4,
+ OPC_6502_A5,
+ OPC_6502_A6,
+ OPC_6502_A7,
+ OPC_6502_A8,
+ OPC_6502_A9,
+ OPC_6502_AA,
+ OPC_6502_AB,
+ OPC_6502_AC,
+ OPC_6502_AD,
+ OPC_6502_AE,
+ OPC_6502_AF,
+ OPC_6502_B0,
+ OPC_6502_B1,
+ OPC_Illegal,
+ OPC_6502_B3,
+ OPC_6502_B4,
+ OPC_6502_B5,
+ OPC_6502_B6,
+ OPC_6502_B7,
+ OPC_6502_B8,
+ OPC_6502_B9,
+ OPC_6502_BA,
+ OPC_6502_BB,
+ OPC_6502_BC,
+ OPC_6502_BD,
+ OPC_6502_BE,
+ OPC_6502_BF,
+ OPC_6502_C0,
+ OPC_6502_C1,
+ OPC_6502_C2,
+ OPC_6502_C3,
+ OPC_6502_C4,
+ OPC_6502_C5,
+ OPC_6502_C6,
+ OPC_6502_C7,
+ OPC_6502_C8,
+ OPC_6502_C9,
+ OPC_6502_CA,
+ OPC_6502_CB,
+ OPC_6502_CC,
+ OPC_6502_CD,
+ OPC_6502_CE,
+ OPC_6502_CF,
+ OPC_6502_D0,
+ OPC_6502_D1,
+ OPC_Illegal,
+ OPC_6502_D3,
+ OPC_6502_D4,
+ OPC_6502_D5,
+ OPC_6502_D6,
+ OPC_6502_D7,
+ OPC_6502_D8,
+ OPC_6502_D9,
+ OPC_6502_DA,
+ OPC_6502_DB,
+ OPC_6502_DC,
+ OPC_6502_DD,
+ OPC_6502_DE,
+ OPC_6502_DF,
+ OPC_6502_E0,
+ OPC_6502_E1,
+ OPC_6502_E2,
+ OPC_6502_E3,
+ OPC_6502_E4,
+ OPC_6502_E5,
+ OPC_6502_E6,
+ OPC_6502_E7,
+ OPC_6502_E8,
+ OPC_6502_E9,
+ OPC_6502_EA,
+ OPC_6502_EB,
+ OPC_6502_EC,
+ OPC_6502_ED,
+ OPC_6502_EE,
+ OPC_6502_EF,
+ OPC_6502_F0,
+ OPC_6502_F1,
+ OPC_Illegal,
+ OPC_6502_F3,
+ OPC_6502_F4,
+ OPC_6502_F5,
+ OPC_6502_F6,
+ OPC_6502_F7,
+ OPC_6502_F8,
+ OPC_6502_F9,
+ OPC_6502_FA,
+ OPC_6502_FB,
+ OPC_6502_FC,
+ OPC_6502_FD,
+ OPC_6502_FE,
+ OPC_6502_FF
+};
+
+
+
/* Opcode handler table for the 65C02 */
static const OPFunc OP65C02Table[256] = {
OPC_6502_00,
@@ -2957,7 +3816,7 @@ static const OPFunc OP65C02Table[256] = {
OPC_65C02_NOP11, // $1B
OPC_65SC02_1C,
OPC_6502_1D,
- OPC_6502_1E,
+ OPC_65C02_1E,
OPC_Illegal, // $1F: BBR1 currently unsupported
OPC_6502_20,
OPC_6502_21,
@@ -2989,13 +3848,13 @@ static const OPFunc OP65C02Table[256] = {
OPC_65C02_NOP11, // $3B
OPC_65SC02_3C,
OPC_6502_3D,
- OPC_6502_3E,
+ OPC_65C02_3E,
OPC_Illegal, // $3F: BBR3 currently unsupported
OPC_6502_40,
OPC_6502_41,
OPC_65C02_NOP22, // $42
OPC_65C02_NOP11, // $43
- OPC_65C02_44, // $44
+ OPC_6502_44, // $44
OPC_6502_45,
OPC_6502_46,
OPC_Illegal, // $47: RMB4 currently unsupported
@@ -3021,7 +3880,7 @@ static const OPFunc OP65C02Table[256] = {
OPC_65C02_NOP11, // $5B
OPC_65C02_5C,
OPC_6502_5D,
- OPC_6502_5E,
+ OPC_65C02_5E,
OPC_Illegal, // $5F: BBR5 currently unsupported
OPC_6502_60,
OPC_6502_61,
@@ -3053,7 +3912,7 @@ static const OPFunc OP65C02Table[256] = {
OPC_65C02_NOP11, // $7B
OPC_65SC02_7C,
OPC_6502_7D,
- OPC_6502_7E,
+ OPC_65C02_7E,
OPC_Illegal, // $7F: BBR7 currently unsupported
OPC_65SC02_80,
OPC_6502_81,
@@ -3188,7 +4047,11 @@ static const OPFunc OP65C02Table[256] = {
/* Tables with opcode handlers */
-static const OPFunc* Handlers[2] = {OP6502Table, OP65C02Table};
+static const OPFunc* Handlers[3] = {
+ OP6502Table,
+ OP65C02Table,
+ OP6502XTable
+};
diff --git a/src/sim65/6502.h b/src/sim65/6502.h
index 39b995793..a7a702521 100644
--- a/src/sim65/6502.h
+++ b/src/sim65/6502.h
@@ -47,7 +47,8 @@
/* Supported CPUs */
typedef enum CPUType {
CPU_6502,
- CPU_65C02
+ CPU_65C02,
+ CPU_6502X
} CPUType;
/* Current CPU */
diff --git a/src/sim65/main.c b/src/sim65/main.c
index 3c7cdc157..76c912c6b 100644
--- a/src/sim65/main.c
+++ b/src/sim65/main.c
@@ -177,10 +177,16 @@ static unsigned char ReadProgramFile (void)
/* Get the CPU type from the file header */
if ((Val = fgetc(F)) != EOF) {
- if (Val != CPU_6502 && Val != CPU_65C02) {
+ switch (Val) {
+ case CPU_6502:
+ case CPU_65C02:
+ case CPU_6502X:
+ CPU = Val;
+ break;
+
+ default:
Error ("'%s': Invalid CPU type", ProgramFile);
}
- CPU = Val;
}
/* Get the address of sp from the file header */
diff --git a/targettest/atari/mem.c b/targettest/atari/mem.c
index bc70aded6..b15b215ed 100644
--- a/targettest/atari/mem.c
+++ b/targettest/atari/mem.c
@@ -21,6 +21,8 @@ unsigned int *MEMTOP = (unsigned int *)741;
unsigned int *MEMLO = (unsigned int *)743;
void *allocmem;
+void code(void) { }
+
int main(void)
{
allocmem = malloc(257);
@@ -35,7 +37,7 @@ int main(void)
printf(" MEMLO = $%04X (%u)\n", *MEMLO, *MEMLO);
printf(" ----------------------\n");
- printf(" main: $%04X (code)\n", &main);
+ printf(" code: $%04X (code)\n", &code);
printf(" data: $%04X (data)\n", &data);
printf(" _dos_type: $%04X (bss)\n", &_dos_type);
printf(" allocmem: $%04X (dyn. data)\n", allocmem);
diff --git a/targettest/pce/conio.c b/targettest/pce/conio.c
index 55f828f26..819e601be 100644
--- a/targettest/pce/conio.c
+++ b/targettest/pce/conio.c
@@ -11,6 +11,8 @@ static char hex[16] = { "0123456789abcdef" };
static char charbuf[0x20];
static char colbuf[0x20];
+void func(void) { }
+
void main(void)
{
int stackvar = 42;
@@ -65,7 +67,7 @@ void main(void)
p[8],p[9],p[10],p[11],p[12],p[13],p[14],p[15]
);
}
- memcpy(p, main, i = 0); /* test that a zero length doesn't copy 64K */
+ memcpy(p, func, i = 0); /* test that a zero length doesn't copy 64K */
gotoxy(0,ysize - 1);
for (i = 0; i < xsize; ++i) {
diff --git a/targettest/scanf-test.c b/targettest/scanf-test.c
index f17b62294..e0ab95756 100644
--- a/targettest/scanf-test.c
+++ b/targettest/scanf-test.c
@@ -159,12 +159,14 @@ static void Pause(void) {
#endif
}
+static void Nil() { }
+
int main(void) {
long n0;
unsigned t;
int c, n1 = 12345, n2, n3;
char s1[80], s2[80];
- void *p1 = main, *p2 = main, *p3 = main, *p4 = main;
+ void *p1 = Nil, *p2 = Nil, *p3 = Nil, *p4 = Nil;
#ifndef USE_STDIO
clrscr();
diff --git a/test/Makefile b/test/Makefile
index 22e425c9c..fbdf8c5d1 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -14,7 +14,9 @@ WORKDIR = ../testwrk
.PHONY: test continue mostlyclean clean
-test: mostlyclean continue
+test:
+ @$(MAKE) mostlyclean
+ @$(MAKE) continue
continue:
@$(MAKE) -C asm all
diff --git a/test/asm/Makefile b/test/asm/Makefile
index dea53f6b2..5b3bff3f8 100644
--- a/test/asm/Makefile
+++ b/test/asm/Makefile
@@ -12,23 +12,25 @@ endif
WORKDIR = ../testwrk/asm
-SUBDIRS = cpudetect opcodes listing val err misc
-
.PHONY: all continue mostlyclean clean
all: mostlyclean continue
-define CALL_template
+continue: mostlyclean
+ @$(MAKE) -C cpudetect all
+ @$(MAKE) -C opcodes all
+ @$(MAKE) -C listing all
+ @$(MAKE) -C val all
+ @$(MAKE) -C err all
+ @$(MAKE) -C misc all
-continue::
- @$(MAKE) -C $1 all
-
-mostlyclean::
- @$(MAKE) -C $1 clean
-
-endef
-
-$(foreach subdir,$(SUBDIRS),$(eval $(call CALL_template,$(subdir))))
+mostlyclean:
+ @$(MAKE) -C cpudetect clean
+ @$(MAKE) -C opcodes clean
+ @$(MAKE) -C listing clean
+ @$(MAKE) -C val clean
+ @$(MAKE) -C err clean
+ @$(MAKE) -C misc clean
clean: mostlyclean
@$(call RMDIR,$(WORKDIR))
diff --git a/test/asm/listing/060-ulabel.s b/test/asm/listing/060-ulabel.s
new file mode 100644
index 000000000..f2e66da87
--- /dev/null
+++ b/test/asm/listing/060-ulabel.s
@@ -0,0 +1,25 @@
+; Test new-style (@:) and legacy-style (:) unnamed labels.
+; Make sure that they have identical behavior.
+
+.ORG $0000
+
+@: nop
+: nop
+.ASSERT @<< = $0000, error
+.ASSERT @-- = $0000, error
+.ASSERT :<< = $0000, error
+.ASSERT :-- = $0000, error
+.ASSERT @< = $0001, error
+.ASSERT @- = $0001, error
+.ASSERT :< = $0001, error
+.ASSERT :- = $0001, error
+.ASSERT @> = $0002, error
+.ASSERT @+ = $0002, error
+.ASSERT :> = $0002, error
+.ASSERT :+ = $0002, error
+.ASSERT @>> = $0003, error
+.ASSERT @++ = $0003, error
+.ASSERT :>> = $0003, error
+.ASSERT :++ = $0003, error
+@: nop
+: nop
diff --git a/test/asm/listing/070-include-macro.inc b/test/asm/listing/070-include-macro.inc
new file mode 100644
index 000000000..0152a7965
--- /dev/null
+++ b/test/asm/listing/070-include-macro.inc
@@ -0,0 +1 @@
+foo:
diff --git a/test/asm/listing/070-include-macro.s b/test/asm/listing/070-include-macro.s
new file mode 100644
index 000000000..aad55cb52
--- /dev/null
+++ b/test/asm/listing/070-include-macro.s
@@ -0,0 +1,13 @@
+.macro IncludeFile FilePath
+ .proc bar
+ .include FilePath
+ .endproc
+.endmacro
+
+IncludeFile "070-include-macro.inc"
+
+.ifdef bar::foo
+ .out "bar::foo is defined"
+.else
+ .out "bar::foo is undefined"
+.endif
diff --git a/test/asm/listing/070-include-repeat.inc b/test/asm/listing/070-include-repeat.inc
new file mode 100644
index 000000000..0eb22a710
--- /dev/null
+++ b/test/asm/listing/070-include-repeat.inc
@@ -0,0 +1 @@
+.out "include file"
diff --git a/test/asm/listing/070-include-repeat.s b/test/asm/listing/070-include-repeat.s
new file mode 100644
index 000000000..20170255f
--- /dev/null
+++ b/test/asm/listing/070-include-repeat.s
@@ -0,0 +1,4 @@
+.repeat 3
+ .include "070-include-repeat.inc"
+ .out "main file"
+.endrepeat
diff --git a/test/asm/listing/ref/070-include-macro.err-ref b/test/asm/listing/ref/070-include-macro.err-ref
new file mode 100644
index 000000000..5faf98c4b
--- /dev/null
+++ b/test/asm/listing/ref/070-include-macro.err-ref
@@ -0,0 +1 @@
+bar::foo is defined
diff --git a/test/asm/listing/ref/070-include-repeat.err-ref b/test/asm/listing/ref/070-include-repeat.err-ref
new file mode 100644
index 000000000..d42e70ee7
--- /dev/null
+++ b/test/asm/listing/ref/070-include-repeat.err-ref
@@ -0,0 +1,6 @@
+include file
+main file
+include file
+main file
+include file
+main file
diff --git a/test/misc/Makefile b/test/misc/Makefile
index cfcae0530..ebae0964e 100644
--- a/test/misc/Makefile
+++ b/test/misc/Makefile
@@ -102,6 +102,14 @@ $(WORKDIR)/bug1265.$1.$2.prg: bug1265.c | $(WORKDIR)
$(LD65) -t sim$2 -o $$@ $$(@:.prg=.o) sim$2.lib $(NULLERR)
$(SIM65) $(SIM65FLAGS) $$@ $(NULLOUT) $(NULLERR)
+# should not compile, but gives different diagnostics in C99 mode than in others
+$(WORKDIR)/bug2515.$1.$2.prg: bug2515.c | $(WORKDIR)
+ $(if $(QUIET),echo misc/bug2515.$1.$2.prg)
+ $(NOT) $(CC65) --standard c99 -t sim$2 -$1 -o $$(@:.prg=.s) $$< 2>$(WORKDIR)/bug2515.$1.$2.out
+ $(ISEQUAL) $(WORKDIR)/bug2515.$1.$2.out bug2515.c99.ref
+ $(NOT) $(CC65) -t sim$2 -$1 -o $$(@:.prg=.s) $$< 2>$(WORKDIR)/bug2515.$1.$2.out
+ $(ISEQUAL) $(WORKDIR)/bug2515.$1.$2.out bug2515.ref
+
# this one requires -Werror
$(WORKDIR)/bug1768.$1.$2.prg: bug1768.c | $(WORKDIR)
$(if $(QUIET),echo misc/bug1768.$1.$2.prg)
diff --git a/test/misc/bug2515.c b/test/misc/bug2515.c
new file mode 100644
index 000000000..62ee52a25
--- /dev/null
+++ b/test/misc/bug2515.c
@@ -0,0 +1,4 @@
+
+#line 13"x"
+#define X"y"
+int main() { foo; }
diff --git a/test/misc/bug2515.c99.ref b/test/misc/bug2515.c99.ref
new file mode 100644
index 000000000..f6cf2fcea
--- /dev/null
+++ b/test/misc/bug2515.c99.ref
@@ -0,0 +1,2 @@
+x:13: Warning: ISO C99 requires whitespace after the macro name
+x:14: Error: Undeclared identifier 'foo'
diff --git a/test/misc/bug2515.ref b/test/misc/bug2515.ref
new file mode 100644
index 000000000..affbaebb9
--- /dev/null
+++ b/test/misc/bug2515.ref
@@ -0,0 +1 @@
+x:14: Error: Undeclared identifier 'foo'
diff --git a/test/ref/Makefile b/test/ref/Makefile
index 5c189c6cb..e82c6de37 100644
--- a/test/ref/Makefile
+++ b/test/ref/Makefile
@@ -50,7 +50,7 @@ ISEQUAL = ..$S..$Stestwrk$Sisequal$(EXE)
# will have to change that, and create said special cases here.
# see discussion in https://github.com/cc65/cc65/issues/2277
CC = gcc
-CFLAGS = -std=gnu17 -O2 -Wall -W -Wextra -funsigned-char -fwrapv -fno-strict-overflow
+CFLAGS = -std=gnu17 -O2 -Wall -W -Wextra -funsigned-char -fwrapv -fno-strict-overflow -Wno-error=implicit-int -Wno-error=int-conversion
.PHONY: all clean
diff --git a/test/ref/bug2134.c b/test/ref/bug2134.c
new file mode 100644
index 000000000..9dd1e5c55
--- /dev/null
+++ b/test/ref/bug2134.c
@@ -0,0 +1,3 @@
+int i = { 0 };
+char* p = { 0 };
+int main() { return 0; }
diff --git a/test/ref/bug2134.cref b/test/ref/bug2134.cref
new file mode 100644
index 000000000..72bbbad04
--- /dev/null
+++ b/test/ref/bug2134.cref
@@ -0,0 +1,2 @@
+bug2134.c:1: Warning: Braces around scalar initializer
+bug2134.c:2: Warning: Braces around scalar initializer
diff --git a/test/ref/custom-reference-error.c b/test/ref/custom-reference-error.c
index e98fb024d..455e0276d 100644
--- a/test/ref/custom-reference-error.c
+++ b/test/ref/custom-reference-error.c
@@ -22,6 +22,5 @@ return_t main(int argc, char* argv[])
n = 0; /* produce an error */
/* produce a warning */
}
-
-int arr[main(0, 0)]; /* produce an error */
int b = 0;
+int arr[b]; /* produce an error */
diff --git a/test/standard/stdint.c b/test/standard/stdint.c
new file mode 100644
index 000000000..29b48346a
--- /dev/null
+++ b/test/standard/stdint.c
@@ -0,0 +1,167 @@
+/* Test definitions from stdint.h */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* All macros from stdint.h must be evaluatable by the preprocessor */
+#if INT8_MIN
+#endif
+#if INT8_MAX
+#endif
+#if INT16_MIN
+#endif
+#if INT16_MAX
+#endif
+#if INT32_MIN
+#endif
+#if INT32_MAX
+#endif
+#if UINT8_MAX
+#endif
+#if UINT16_MAX
+#endif
+#if UINT32_MAX
+#endif
+#if INT_LEAST8_MIN
+#endif
+#if INT_LEAST8_MAX
+#endif
+#if INT_LEAST16_MIN
+#endif
+#if INT_LEAST16_MAX
+#endif
+#if INT_LEAST32_MIN
+#endif
+#if INT_LEAST32_MAX
+#endif
+#if UINT_LEAST8_MAX
+#endif
+#if UINT_LEAST16_MAX
+#endif
+#if UINT_LEAST32_MAX
+#endif
+#if INT_FAST8_MIN
+#endif
+#if INT_FAST8_MAX
+#endif
+#if INT_FAST16_MIN
+#endif
+#if INT_FAST16_MAX
+#endif
+#if INT_FAST32_MIN
+#endif
+#if INT_FAST32_MAX
+#endif
+#if UINT_FAST8_MAX
+#endif
+#if UINT_FAST16_MAX
+#endif
+#if UINT_FAST32_MAX
+#endif
+#if INTPTR_MIN
+#endif
+#if INTPTR_MAX
+#endif
+#if UINTPTR_MAX
+#endif
+#if INTMAX_MIN
+#endif
+#if INTMAX_MAX
+#endif
+#if UINTMAX_MAX
+#endif
+#if PTRDIFF_MIN
+#endif
+#if PTRDIFF_MAX
+#endif
+#if SIG_ATOMIC_MIN
+#endif
+#if SIG_ATOMIC_MAX
+#endif
+#if SIZE_MAX
+#endif
+
+#define SMIN(type) ((type)(1L << (sizeof(type) * CHAR_BIT - 1)))
+#define SMAX(type) ((type)(~SMIN(type)))
+#define UMAX(type) ((type)(~(type)0))
+
+#define SMIN_CHECK(type, val) \
+ if (SMIN(type) != val) { \
+ ++failures; \
+ printf("Mismatch for %s, minimum (%ld) is not %s (%ld)\n", \
+ #type, (long)SMIN(type), #val, (long)val); \
+ }
+#define SMAX_CHECK(type, val) \
+ if (SMAX(type) != val) { \
+ ++failures; \
+ printf("Mismatch for %s, maximum (%ld) is not %s (%ld)\n", \
+ #type, (long)SMAX(type), #val, (long)val); \
+ }
+#define UMAX_CHECK(type, val) \
+ if (UMAX(type) != val) { \
+ ++failures; \
+ printf("Mismatch for %s, maximum (%lu) is not %s (%lu)\n", \
+ #type, (unsigned long)UMAX(type), #val, \
+ (unsigned long)val); \
+ }
+
+static unsigned failures = 0;
+
+int main()
+{
+ SMIN_CHECK(int8_t, INT8_MIN);
+ SMAX_CHECK(int8_t, INT8_MAX);
+ SMIN_CHECK(int16_t, INT16_MIN);
+ SMAX_CHECK(int16_t, INT16_MAX);
+ SMIN_CHECK(int32_t, INT32_MIN);
+ SMAX_CHECK(int32_t, INT32_MAX);
+ UMAX_CHECK(uint8_t, UINT8_MAX);
+ UMAX_CHECK(uint16_t, UINT16_MAX);
+ UMAX_CHECK(uint32_t, UINT32_MAX);
+
+ SMIN_CHECK(int_least8_t, INT_LEAST8_MIN);
+ SMAX_CHECK(int_least8_t, INT_LEAST8_MAX);
+ SMIN_CHECK(int_least16_t, INT_LEAST16_MIN);
+ SMAX_CHECK(int_least16_t, INT_LEAST16_MAX);
+ SMIN_CHECK(int_least32_t, INT_LEAST32_MIN);
+ SMAX_CHECK(int_least32_t, INT_LEAST32_MAX);
+ UMAX_CHECK(uint_least8_t, UINT_LEAST8_MAX);
+ UMAX_CHECK(uint_least16_t, UINT_LEAST16_MAX);
+ UMAX_CHECK(uint_least32_t, UINT_LEAST32_MAX);
+
+ SMIN_CHECK(int_fast8_t, INT_FAST8_MIN);
+ SMAX_CHECK(int_fast8_t, INT_FAST8_MAX);
+ SMIN_CHECK(int_fast16_t, INT_FAST16_MIN);
+ SMAX_CHECK(int_fast16_t, INT_FAST16_MAX);
+ SMIN_CHECK(int_fast32_t, INT_FAST32_MIN);
+ SMAX_CHECK(int_fast32_t, INT_FAST32_MAX);
+ UMAX_CHECK(uint_fast8_t, UINT_FAST8_MAX);
+ UMAX_CHECK(uint_fast16_t, UINT_FAST16_MAX);
+ UMAX_CHECK(uint_fast32_t, UINT_FAST32_MAX);
+
+ SMIN_CHECK(intptr_t, INTPTR_MIN);
+ SMAX_CHECK(intptr_t, INTPTR_MAX);
+ UMAX_CHECK(uintptr_t, UINTPTR_MAX);
+
+ SMIN_CHECK(intmax_t, INTMAX_MIN);
+ SMAX_CHECK(intmax_t, INTMAX_MAX);
+ UMAX_CHECK(uintmax_t, UINTMAX_MAX);
+
+ SMIN_CHECK(ptrdiff_t, PTRDIFF_MIN);
+ SMAX_CHECK(ptrdiff_t, PTRDIFF_MAX);
+
+#if SIG_ATOMIC_MIN < 0
+ SMIN_CHECK(sig_atomic_t, SIG_ATOMIC_MIN);
+ SMAX_CHECK(sig_atomic_t, SIG_ATOMIC_MAX);
+#else
+ UMAX_CHECK(sig_atomic_t, SIG_ATOMIC_MAX);
+#endif
+
+ UMAX_CHECK(size_t, SIZE_MAX);
+
+ return failures;
+}
diff --git a/test/val/bug2458.c b/test/val/bug2458.c
new file mode 100644
index 000000000..1494a7946
--- /dev/null
+++ b/test/val/bug2458.c
@@ -0,0 +1,10 @@
+#define str(arg) #arg
+#include str(bug2458.h) /* Ok, macro replacement */
+
+#define string foo
+#include /* Ok, no macro replacement */
+
+int main()
+{
+ return 0;
+}
diff --git a/test/val/bug2458.h b/test/val/bug2458.h
new file mode 100644
index 000000000..8b1378917
--- /dev/null
+++ b/test/val/bug2458.h
@@ -0,0 +1 @@
+
diff --git a/test/val/bug2461.c b/test/val/bug2461.c
new file mode 100644
index 000000000..e8340b224
--- /dev/null
+++ b/test/val/bug2461.c
@@ -0,0 +1,67 @@
+/* related to bug #2461 */
+
+/* Note: The values for MASK1, MASK2, the return values of GarbleAX and the
+ * arguments for CALC() are carefully chosen to elicit the bug.
+ */
+
+#include
+
+#define MASK1 0x000FU
+#define MASK2 0x00FFU
+#define CALC(num, op) (((num) & (~MASK1)) op ((num) & MASK2))
+
+static unsigned Failures = 0;
+static unsigned TestCount = 0;
+
+unsigned GarbleAX(void)
+{
+ static const unsigned Garbage[] = {
+ 0x1234, 0x0000, 0x1234, 0x1234
+ };
+ return Garbage[TestCount - 1];
+}
+
+unsigned WrongAdd(unsigned num)
+{
+ unsigned ret=GarbleAX();
+ return CALC(num, +);
+}
+
+unsigned WrongAnd(unsigned num)
+{
+ unsigned ret=GarbleAX();
+ return CALC(num, &);
+}
+
+unsigned WrongOr(unsigned num)
+{
+ unsigned ret=GarbleAX();
+ return CALC(num, |);
+}
+
+unsigned WrongXor(unsigned num)
+{
+ unsigned ret=GarbleAX();
+ return CALC(num, ^);
+}
+
+void Test(unsigned (*F)(unsigned), unsigned Num, unsigned Ref)
+{
+ unsigned Res;
+ ++TestCount;
+ Res = F(Num);
+ if (Res != Ref) {
+ printf("Test %u failed: got %04X, expected %04X\n", TestCount, Res, Ref);
+ ++Failures;
+ }
+}
+
+int main(void)
+{
+ Test(WrongAdd, 0x4715, CALC(0x4715, +));
+ Test(WrongAnd, 0x4715, CALC(0x4715, &));
+ Test(WrongOr, 0x4715, CALC(0x4715, |));
+ Test(WrongXor, 0x4715, CALC(0x4715, ^));
+ printf("Failures: %u\n", Failures);
+ return Failures;
+}
diff --git a/test/val/bug2520.c b/test/val/bug2520.c
new file mode 100644
index 000000000..7a216df4d
--- /dev/null
+++ b/test/val/bug2520.c
@@ -0,0 +1,4 @@
+#if (1 ? 2 : 0) != 2
+#error
+#endif
+int main() { return 0; }
diff --git a/test/val/nullptr.c b/test/val/nullptr.c
index e64b82ee2..a5b72e8c5 100644
--- a/test/val/nullptr.c
+++ b/test/val/nullptr.c
@@ -28,6 +28,8 @@ struct S {
} \
} while(0);
+void func() { }
+
int main()
{
int a;
@@ -60,7 +62,7 @@ int main()
TEST_NON_NULL(((struct S*)&a)->a)
/* Non-null pointer obtained with cast and -> */
- TEST_NON_NULL(((struct S*)&main)->a)
+ TEST_NON_NULL(((struct S*)&func)->a)
if (failures != 0)
{
diff --git a/test/val/pragmas.c b/test/val/pragmas.c
new file mode 100644
index 000000000..802c7a5c3
--- /dev/null
+++ b/test/val/pragmas.c
@@ -0,0 +1,44 @@
+/* Note: This tests just if the #pragmas are understood. It doesn't test if
+** they do really work. This would require much more work.
+*/
+
+void func(void);
+#pragma align(push, 1024)
+#pragma allow-eager-inline(push, on)
+#pragma allow_eager_inline(pop)
+#pragma bss-name(push, "BSS")
+#pragma bss_name(pop)
+#pragma charmap(1, 1)
+#pragma check-stack(on)
+#pragma check_stack(off)
+#pragma code-name(push, "CODE")
+#pragma code_name("CODE")
+#pragma codesize(200)
+#pragma data-name("DATA")
+#pragma data_name("DATA")
+#pragma inline-stdfuncs(off)
+#pragma inline_stdfuncs(on)
+#pragma local-strings(off)
+#pragma local_strings(off)
+#pragma message("in a bottle")
+#pragma optimize(off)
+#pragma register-vars(off)
+#pragma register_vars(on)
+#pragma regvaraddr(on)
+#pragma rodata-name("RODATA")
+#pragma rodata_name("RODATA")
+#pragma signed-chars(off)
+#pragma signed_chars(on)
+#pragma static-locals(off)
+#pragma static_locals(on)
+#pragma warn(unused-param, on)
+#pragma wrapped-call(push, func, 0) // push is required for this #pragma
+#pragma wrapped_call(push, func, 1)
+#pragma writable-strings(on)
+#pragma writable_strings(off)
+#pragma zpsym("func")
+
+int main ()
+{
+ return 0;
+}
diff --git a/test/val/stpcpy.c b/test/val/stpcpy.c
new file mode 100644
index 000000000..1cc6458ed
--- /dev/null
+++ b/test/val/stpcpy.c
@@ -0,0 +1,53 @@
+// 2024-07-15 Sven Michael Klose
+
+#include
+#include
+#include
+#include
+
+#define STR_SHORT "Hello, World!"
+#define STR_LONG "This is a longer test string for stpcpy."
+
+char dest[512];
+char multi_page[300];
+
+int
+main ()
+{
+ const char *src_empty;
+ const char *src_short;
+ const char *src_long;
+ char *end;
+
+ src_empty = "";
+ end = stpcpy (dest, src_empty);
+ assert(!strcmp (dest, src_empty));
+ assert(!*end);
+ assert(end == dest);
+ printf ("Test 1 passed.\n");
+
+ src_short = STR_SHORT;
+ end = stpcpy (dest, src_short);
+ assert(!strcmp (dest, src_short));
+ assert(!*end);
+ assert(end == &dest[sizeof (STR_SHORT) - 1]);
+ printf ("Test 2 passed.\n");
+
+ src_long = STR_LONG;
+ end = stpcpy (dest, src_long);
+ assert(!strcmp (dest, src_long));
+ assert(!*end);
+ assert(end == &dest[sizeof (STR_LONG) - 1]);
+ printf ("Test 3 passed.\n");
+
+ memset(multi_page, 'a', sizeof(multi_page)-1);
+ multi_page[sizeof(multi_page)-1] = '\0';
+ end = stpcpy (dest, multi_page);
+ assert(!strcmp (dest, multi_page));
+ assert(!*end);
+ assert(end == &dest[sizeof (multi_page) - 1]);
+ printf ("Test 4 passed.\n");
+
+ printf ("All tests passed.\n");
+ return EXIT_SUCCESS;
+}
diff --git a/test/val/strstr-test.c b/test/val/strstr-test.c
new file mode 100644
index 000000000..5c8a147b0
--- /dev/null
+++ b/test/val/strstr-test.c
@@ -0,0 +1,41 @@
+#include
+#include
+#include
+
+int fails = 0;
+
+#define STRSTR_TEST(needle,expected) \
+ if (strstr(haystack, (needle)) != (expected)) { \
+ printf("strstr failure: expected %p for \"%s\", " \
+ "got %p\n", \
+ expected, needle, strstr(haystack, (needle)));\
+ fails++; \
+ }
+
+#define STRCASESTR_TEST(needle,expected) \
+ if (strcasestr(haystack, (needle)) != (expected)) { \
+ printf("strcasestr failure: expected %p for \"%s\", " \
+ "got %p\n", \
+ expected, needle, strcasestr(haystack, (needle)));\
+ fails++; \
+ }
+
+int main (void)
+{
+ const char *haystack = "This is a string to search in";
+
+ STRSTR_TEST("This is", haystack + 0);
+ STRSTR_TEST("a string", haystack + 8);
+ STRSTR_TEST("This is a string to search in", haystack);
+ STRSTR_TEST("search in", haystack + 20);
+ STRSTR_TEST("This is a string to search in with extra chars", NULL);
+ STRSTR_TEST("nowhere", NULL);
+
+ STRCASESTR_TEST("this is", haystack + 0);
+ STRCASESTR_TEST("a STRING", haystack + 8);
+ STRCASESTR_TEST("this is a string TO search in", haystack);
+ STRCASESTR_TEST("This is a string to search in with extra chars", NULL);
+ STRCASESTR_TEST("search IN", haystack + 20);
+
+ return fails;
+}
diff --git a/test/val/strtok.c b/test/val/strtok.c
new file mode 100644
index 000000000..4d63bfb2a
--- /dev/null
+++ b/test/val/strtok.c
@@ -0,0 +1,41 @@
+#include
+#include
+#include
+
+void
+error (void)
+{
+ printf ("strtok() test failed!\n");
+ exit (EXIT_FAILURE);
+}
+
+void
+test (char * s)
+{
+ if (strcmp ("test", strtok (s, "/")))
+ error ();
+ if (strcmp ("foo", strtok (NULL, "/")))
+ error ();
+ if (strcmp ("bar", strtok (NULL, "/")))
+ error ();
+ if (strtok (NULL, "/"))
+ error ();
+ if (strtok (NULL, "/"))
+ error ();
+}
+
+int
+main (void)
+{
+ char s1[] = "test/foo/bar";
+ char s2[] = "/test/foo/bar";
+ char s3[] = "//test/foo/bar";
+ char s4[] = "//test/foo/bar//";
+
+ test (s1);
+ test (s2);
+ test (s3);
+ test (s4);
+
+ return EXIT_SUCCESS;
+}
diff --git a/test/val/time-test2.c b/test/val/time-test2.c
new file mode 100644
index 000000000..725bbd0e6
--- /dev/null
+++ b/test/val/time-test2.c
@@ -0,0 +1,61 @@
+/* Another test for time() */
+
+#include
+#include
+
+static int failures = 0;
+#define INV_TIME ((time_t)-1)
+#define TEST_TIME ((time_t)0x78AB1234)
+
+/* We supply our own clock_gettime function so we can control the values
+** supplied to time() internally.
+*/
+static time_t timeval;
+static int timeres;
+int __fastcall__ clock_gettime (clockid_t, struct timespec *tp)
+{
+ /* Don't touch tp in case of an error */
+ if (timeres != -1) {
+ tp->tv_sec = timeval;
+ tp->tv_nsec = 0;
+ }
+ return timeres;
+}
+
+int main()
+{
+ time_t res, pres;
+
+ /* First test: Force time() to return an error. Check that both, the
+ ** returned value and the value passed via pointer are (time_t)-1.
+ */
+ timeval = 42;
+ timeres = -1;
+ res = time(&pres);
+ if (res != INV_TIME || pres != INV_TIME) {
+ printf("Error in test 1\n");
+ ++failures;
+ }
+
+ /* Second test: Return a valid value and check both results */
+ timeval = TEST_TIME;
+ timeres = 0;
+ res = time(&pres);
+ if (res != TEST_TIME || pres != TEST_TIME) {
+ printf("Error in test 2\n");
+ ++failures;
+ }
+
+ /* Third test: Return no error but an invalid value and check both
+ ** results
+ */
+ timeval = INV_TIME;
+ timeres = 0;
+ res = time(&pres);
+ if (res != INV_TIME || pres != INV_TIME) {
+ printf("Error in test 3\n");
+ ++failures;
+ }
+
+ return failures;
+}