1
0
mirror of https://github.com/cc65/cc65.git synced 2025-04-08 19:38:55 +00:00

Merge branch 'cc65:master' into master

This commit is contained in:
rumbledethumps 2024-09-29 18:36:34 -07:00 committed by GitHub
commit e373aa2d3f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
108 changed files with 5519 additions and 2248 deletions

View File

@ -9,7 +9,7 @@ nl='
'
nl=$'\n'
r1="${nl}$"
FILES=`find $CHECK_PATH -type f \( -name \*.inc -o -name Makefile -o -name \*.cfg -o -name \*.\[chs\] -o -name \*.mac -o -name \*.asm -o -name \*.sgml \) -print | while read f; do
FILES=`find $CHECK_PATH -type f -size +0 \( -name \*.inc -o -name Makefile -o -name \*.cfg -o -name \*.\[chs\] -o -name \*.mac -o -name \*.asm -o -name \*.sgml \) -print | while read f; do
t=$(tail -c2 $f; printf x)
[[ ${t%x} =~ $r1 ]] || echo "$f"
done`

View File

@ -35,7 +35,7 @@ jobs:
run: make -j2 lib QUIET=1
- name: Run the regression tests.
shell: bash
run: make test QUIET=1
run: make -j2 test QUIET=1
- name: Test that the samples can be built.
run: make -C samples platforms
- name: Test that the targettest programs can be built.
@ -89,4 +89,4 @@ jobs:
- name: Run the regression tests (make test)
shell: cmd
run: make test QUIET=1 SHELL=cmd
run: make -j2 test QUIET=1 SHELL=cmd

View File

@ -59,7 +59,7 @@ jobs:
run: make -j2 lib QUIET=1
- name: Run the regression tests.
shell: bash
run: make test QUIET=1
run: make -j2 test QUIET=1
- name: Test that the samples can be built.
shell: bash
run: make -j2 samples

View File

@ -70,7 +70,7 @@ jobs:
- name: Run the regression tests (make test)
if: steps.check-sha.outputs.cache-hit != 'true'
shell: cmd
run: make test QUIET=1 SHELL=cmd
run: make -j2 test QUIET=1 SHELL=cmd
- name: Test that the samples can be built (make samples)
if: steps.check-sha.outputs.cache-hit != 'true'

View File

@ -1,188 +1,321 @@
This document contains all kinds of information that you should know if you want to contribute to the cc65 project. Before you start, please read all of it. If something is not clear to you, please ask - this document is an ongoing effort and may well be incomplete.
Contributing to cc65
====================
Also, before you put a lot of work into implementing something you want to contribute, please get in touch with one of the developers and ask if what you are going to do is actually wanted and has a chance of being merged. Perhaps someone else is already working on it, or perhaps what you have in mind is not how we'd expect it to be - talking to us before you start might save you a lot of work in those cases.
This document contains all kinds of information that you
should know if you want to contribute to the cc65 project.
Before you start, please read all of it. If something is not
clear to you, please ask - this document is an ongoing effort
and may well be incomplete.
(''Note:'' The word "must" indicates a requirement. The word "should" indicates a recomendation.)
Also, before you put a lot of work into implementing
something you want to contribute, please get in touch with
one of the developers and ask if what you are going to do is
actually wanted and has a chance of being merged. Perhaps
someone else is already working on it, or perhaps what you
have in mind is not how we'd expect it to be - talking to us
before you start might save you a lot of work in those cases.
*this is work in progress and is constantly updated - if in doubt, please ask*
(''Note:'' The word "must" indicates a requirement. The word
"should" indicates a recomendation.)
# generally
*this is work in progress and is constantly updated - if in
doubt, please ask*
* You must obey these rules when contributing new code or documentation to cc65. We are well aware that not all existing code may respect all rules outlined here - but this is no reason for you not to respect them.
* One commit/patch/PR per issue. Do not mix several things unless they are very closely related.
* Sometimes when you make a PR, it may break completely unrelated tests. However, any PR is expected to merge cleanly with no failures. That means in practise that you are expected to fix/update the failing tests if required - for example this might be needed if you make changes to the compiler that changes the format of error- or warning messages. In that case you might have to update some reference files in the testbench. Obviously still check if that is actually the right thing to do ;)
# Generally
* You must obey these rules when contributing new code or
documentation to cc65. We are well aware that not all
existing code may respect all rules outlined here - but this
is no reason for you not to respect them.
* One commit/patch/PR per issue. Do not mix several things
unless they are very closely related.
* Sometimes when you make a PR, it may break completely
unrelated tests. However, any PR is expected to merge
cleanly with no failures. That means in practise that you
are expected to fix/update the failing tests if required -
for example this might be needed if you make changes to the
compiler that changes the format of error- or warning
messages. In that case you might have to update some
reference files in the testbench. Obviously still check if
that is actually the right thing to do. ;)
# Codestyle rules
## All Sources
## All sources
### Line endings
All files must only contain Unix style 'LF' line endings. Please configure your editors accordingly.
All files must only contain Unix style 'LF' line endings.
Please configure your editors accordingly.
### TABs and spaces
This is an ongoing controversial topic - everyone knows that. However, the following is how we do it :)
This is an ongoing controversial topic - everyone knows
that. However, the following is how we do it :)
* TAB characters must be expanded to spaces.
* 4 spaces per indention level (rather than 8) are preferred, especially if there are many different levels.
* 4 spaces per indention level (rather than 8) are
preferred, especially if there are many different levels.
* No extra spaces at the end of lines.
* All text files must end with new-line characters. Don't leave the last line "dangling".
* All text files must end with new-line characters. Don't
leave the last line "dangling".
The (bash) scripts used to check the above rules can be found in ```.github/check```. You can also run all checks using ```make check```.
The (bash) scripts used to check the above rules can be
found in ```.github/check```. You can also run all checks
using ```make check```.
### Identifiers and Symbol names
### Identifiers and symbol names
The C Standard defines certain identifiers and symbol names, which we can not use
in our code. Since it is not always obvious which parts of the library code will
actually end up in a linked program, the following applies to ALL of the library.
The C Standard defines certain identifiers and symbol names,
which we can not use in our code. Since it is not always
obvious which parts of the library code will actually end up
in a linked program, the following applies to ALL of the
library.
Any non standard identifier/symbol/function that is exported from source files,
or appears in header files:
Any non standard identifier/symbol/function that is exported
from source files, or appears in header files:
* must not be in the "_symbol" form in C, or "__symbol" form in assembly.
* must start with (at least) two (C Code) or three (assembly code) underscores, unless the symbol appears in a non standard header file.
* must not be in the "_symbol" form in C, or "__symbol" form
in assembly,
* must start with (at least) two (C Code) or three (assembly
code) underscores, unless the symbol appears in a non
standard header file.
This is likely more than the standard dictates us to do - but it is certainly
standard compliant - and easy to remember.
This is likely more than the standard dictates us to do -
but it is certainly standard compliant - and easy to
remember.
Also see the discussion in https://github.com/cc65/cc65/issues/1796
Also see the discussion in
https://github.com/cc65/cc65/issues/1796
### misc
### Miscellaneous
* 80 characters is the desired maximum width of files. But, it isn't a "strong" rule; sometimes, you will want to type longer lines, in order to keep the parts of expressions or comments together on the same line.
* 80 characters is the desired maximum width of files. But,
it isn't a "strong" rule; sometimes, you will want to type
longer lines, in order to keep the parts of expressions or
comments together on the same line.
* You should avoid typing non-ASCII characters.
* If you change "normal" source code into comments, then you must add a comment about why that code is a comment.
* When you want to create a comment from several lines of code, you should use preprocessor lines, instead of ```/* */``` or "```;```". Example:
<pre>
* If you change "normal" source code into comments, then you
must add a comment about why that code is a comment.
* When you want to create a comment from several lines of
code, you should use preprocessor lines, instead of ```/*
*/``` or "```;```". Example:
~~~C
#if 0
one ();
two ();
three = two () + one ();
one (); two ();
three = two () + one ();
#endif
</pre>
~~~
* You should type upper case characters for hex values.
* When you type zero-page addresses in hexadecimal, you should type two hex characters (after the hex prefix). When you type non-zero-page addresses in hex, you should type four hex characters.
* When you type lists of addresses, it is a good idea to sort them in ascending numerical order. That makes it easier for readers to build mental pictures of where things are in an address space. And, it is easier to see how big the variables and buffers are. Example:
<pre>
* When you type zero-page addresses in hexadecimal, you
should type two hex characters (after the hex prefix).
When you type non-zero-page addresses in hex, you should
type four hex characters.
* When you type lists of addresses, it is a good idea to
sort them in ascending numerical order. That makes it
easier for readers to build mental pictures of where things
are in an address space. And, it is easier to see how big
the variables and buffers are. Example:
~~~asm
xCoord := $0703
yCoord := $0705 ; (this address implies that xCoord is 16 bits)
cmdbuf := $0706 ; (this address implies that yCoord is 8 bits)
cmdlen := $0786 ; (this address implies that cmdbuf is 128 bytes)
yCoord := $0705 ; (this address implies that xCoord is 16 bits)
cmdbuf := $0706 ; (this address implies that yCoord is 8 bits)
cmdlen := $0786 ; (this address implies that cmdbuf is 128 bytes)
color := $0787
</pre>
~~~
## C Sources
## C sources
The following is still very incomplete - if in doubt please look at existing sourcefiles and adapt to the existing style
The following is still very incomplete - if in doubt please
look at existing sourcefiles and adapt to the existing style.
* Your files should generally obey the C89 standard, with a few C99 things (this is a bit similar to what cc65 itself supports). The exceptions are:
* use stdint.h for variables that require a certain bit size
* In printf-style functions use the PRIX64 (and similar) macros to deal with 64bit values (from inttypes.h)
This list is not necessarily complete - if in doubt, please ask.
Your files should generally obey the C89 standard, with a
few C99 things (this is a bit similar to what cc65 itself
supports). The exceptions are:
* Use stdint.h for variables that require a certain bit size
* In printf-style functions use the PRIX64 (and similar)
macros to deal with 64bit values (from inttypes.h) This
list is not necessarily complete - if in doubt, please ask.
* We generally have a "no warnings" policy
* Warnings must not be hidden by using typecasts - fix the code instead
* Warnings must not be hidden by using typecasts - fix the
code instead
* The normal indentation width should be four spaces.
* You must use ANSI C comments (```/* */```); you must not use C++ comments (```//```).
* When you add functions to an existing file, you should separate them by the same number of blank lines that separate the functions that already are in that file.
* All function declarations must be followed by a comment block that tells at least briefly what the function does, what the parameters are, and what is returned. This comment must sit between the declaration and the function body, like this:
<pre>
* You must use ANSI C comments (```/* */```); you must not
use C++ comments (```//```).
* When you add functions to an existing file, you should
separate them by the same number of blank lines that
separate the functions that already are in that file.
* All function declarations must be followed by a comment
block that tells at least briefly what the function does,
what the parameters are, and what is returned. This comment
must sit between the declaration and the function body, like
this:
~~~C
int foo(int bar)
/* Add 1 to bar, takes bar and returns the result */
{
return bar + 1;
}
</pre>
* When a function's argument list wraps around to a next line, you should indent that next line by either the normal width or enough spaces to align it with the arguments on the previous line.
* All declarations in a block must be at the beginning of that block.
* You should put a blank line between a list of local variable declarations and the first line of code.
* Always use curly braces even for single statements after ```if```, and the single statement should go into a new line.
* Use "cuddling" braces, ie the opening brace goes in the same line as the ```if```:
<pre>
~~~
* When a function's argument list wraps around to a next
line, you should indent that next line by either the
normal width or enough spaces to align it with the arguments
on the previous line.
* All declarations in a block must be at the beginning of
that block.
* You should put a blank line between a list of local
variable declarations and the first line of code.
* Always use curly braces even for single statements after
```if```, and the single statement should go into a new
line.
* Use "cuddling" braces, ie the opening brace goes in the
same line as the ```if```:
~~~C
if (foo > 42) {
bar = 23;
}
</pre>
* Should the ```if``` statement be followed by an empty conditional block, there should be a comment telling why this is the case
<pre>
if (check()) {
/* nothing happened, do nothing */
}
</pre>
* You must separate function names and parameter/argument lists by one space.
* When declaring/defining pointers, you must put the asterisk (```*```) next to the data type, with a space between it and the variable's name. Examples:
<pre>
int* namedPtr[5];
char* nextLine (FILE* f);
</pre>
~~~
* Should the ```if``` statement be followed by an empty
conditional block, there should be a comment telling why
this is the case:
~~~C
if (check()) { /* nothing happened, do nothing */ }
~~~
* You must separate function names and parameter/argument
lists by one space.
* When declaring/defining pointers, you must put the
asterisk (```*```) next to the data type, with a space
between it and the variable's name. Examples:
~~~C
int* namedPtr[5];
char* nextLine (FILE* f);
~~~
### Header files
Headers that belong to the standard library (libc) must conform with the C standard. That means:
* all non standard functions, or functions that only exist in a certain standard, should be in #ifdefs
* the same is true for macros or typedefs
<pre>
#if __CC65_STD__ == __CC65_STD_C99__
/* stuff that only exists in C99 here */
#endif
#if __CC65_STD__ == __CC65_STD_CC65__
/* non standard stuff here */
#endif
</pre>
You can refer to Annex B of the ISO C99 standard ([here](https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf) is the draft).
* All Headers should start with a copyright/license banner
* Function prototypes must be a single line, not contain the redundant
"extern" keyword, and followed by a brief comment that explains what
the function does, and separated from the next prototype by a blank
line:
## Assembly Sources
~~~C
void __fastcall__ cclear (unsigned char length);
/* Clear part of a line (write length spaces). */
* Op-code mnemonics must have lower-case letters. The names of instruction macroes may have upper-case letters.
* Op-codes must use their official and commonly used mnemonics, ie bcc and bcs and not bgt and blt
* Hexadecimal number constants should be used except where decimal or binary numbers make much more sense in that constant's context.
~~~
Headers that belong to the standard library (libc) must
conform with the C standard. That means:
* All non standard functions, or functions that only exist
in a certain standard, should be in #ifdefs
* The same is true for macros or typedefs.
You can refer to Annex B of the ISO C99 standard
([here](https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf)
is the draft). Example:
~~~C
#if __CC65_STD__ == __CC65_STD_C99__ /* stuff that only exists in C99 here */
#endif
#if __CC65_STD__ == __CC65_STD_CC65__ /* non standard stuff here */
#endif </pre>
~~~
## Assembly sources
* Opcode mnemonics must have lower-case letters. The names
of instruction macroes may have upper-case letters.
* Opcodes must use their official and commonly used
mnemonics, ie 'bcc' and 'bcs' and not 'bgt' and 'blt'.
* Hexadecimal number constants should be used except where
decimal or binary numbers make much more sense in that
constant's context.
* Hexadecimal letters should be upper-case.
* When you set two registers or two memory locations to an immediate 16-bit zero, you should use the expressions ```#<$0000``` and ```#>$0000``` (they make it obvious where you are putting the lower and upper bytes).
* If a function is declared to return a char-sized value, it actually must return an integer-sized value. (When cc65 promotes a returned value, it sometimes assumes that the value already is an integer.) This must be done in one of the following ways:
<pre>
* When you set two registers or two memory locations to an
immediate 16-bit zero, you should use the expressions
```#<$0000``` and ```#>$0000``` (they make it obvious where
you are putting the lower and upper bytes).
* If a function is declared to return a char-sized value, it
actually must return an integer-sized value. (When cc65
promotes a returned value, it sometimes assumes that the value
already is an integer.)
This must be done in one of the following ways:
~~~asm
lda #RETURN_VALUE
ldx #0 ; Promote char return value
</pre>
or, if the value is 0, you can use:
<pre>
; If the value is 0, you can use:
lda #RETURN_VALUE
.assert RETURN_VALUE = 0
tax
</pre>
sometimes jumping to return0 could save a byte:
<pre>
; Sometimes jumping to 'return 0' could save a byte:
.assert RETURN_VALUE = 0
jmp return 0
</pre>
* Functions, that are intended for a platform's system library, should be optimized as much as possible.
* Sometimes, there must be a trade-off between size and speed. If you think that a library function won't be used often, then you should make it small. Otherwise, you should make it fast.
* Comments that are put on the right side of instructions must be aligned (start in the same character columns).
* Assembly source fields (label, operation, operand, comment) should start ''after'' character columns that are multiples of eight (such as 1, 9, 17, 33, and 41).
~~~
* Functions, that are intended for a platform's system
library, should be optimized as much as possible.
* Sometimes, there must be a trade-off between size and
speed. If you think that a library function won't be used
often, then you should make it small. Otherwise, you should
make it fast.
* Comments that are put on the right side of instructions
must be aligned (start in the same character columns).
* Assembly source fields (label, operation, operand,
comment) should start ''after'' character columns that are
multiples of eight (such as 1, 9, 17, 33, and 41).
## LinuxDoc Sources
## LinuxDoc sources
* TAB characters must be expanded to spaces.
* All text files must end with new-line characters. Don't leave the last line "dangling".
* All text files must end with new-line characters. Don't
leave the last line "dangling".
* 80 characters is the desired maximum width of files.
* You should avoid typing non-ASCII characters.
* You should put blank lines between LinuxDoc sections:
* Three blank lines between ```<sect>``` sections.
* Two blank lines between ```<sect1>``` sections.
* One blank line between other sections.
* Three blank lines between ```<sect>``` sections.
* Two blank lines between ```<sect1>``` sections.
* One blank line between other sections.
# Library implementation rules
* By default the toolchain must output a "standard" binary for the platform, no emulator formats, no extra headers used by tools. If the resulting binaries can not be run as is on emulators or eg flash cartridges, the process of converting them to something that can be used with these should be documented in the user manual.
* Generally every function should live in a seperate source file - unless the functions are so closely related that splitting makes no sense.
* Source files should not contain commented out code - if they do, there should be a comment that explains why that commented out code exists.
* By default the toolchain must output a "standard" binary
for the platform, no emulator formats, no extra headers
used by tools. If the resulting binaries can not be run as
is on emulators or eg flash cartridges, the process of
converting them to something that can be used with these
should be documented in the user manual.
* Generally every function should live in a seperate source
file - unless the functions are so closely related that
splitting makes no sense.
* Source files should not contain commented out code - if
they do, there should be a comment that explains why that
commented out code exists.
# Makefile rules
* Makefiles must generally work on both *nix (ba)sh and windows cmd.exe.
* Makefiles must not use external tools that are not provided by the cc65 toolchain itself.
* Makefiles must generally work on both *nix (ba)sh and
windows cmd.exe.
* Makefiles must not use external tools that are not
provided by the cc65 toolchain itself.
The only exception to the above are actions that are exclusive to the github actions - those may rely on bash and/or linux tools.
The only exception to the above are actions that are exclusive
to the github actions - those may rely on bash and/or linux tools.
# Documentation rules
@ -192,107 +325,42 @@ The only exception to the above are actions that are exclusive to the github act
## Wiki
* The Wiki is strictly for additional information that does not fit into the regular user manual (LinuxDoc). The wiki must not duplicate any information that is present in the user manual
* The Wiki is strictly for additional information that does
not fit into the regular user manual (LinuxDoc). The wiki
must not duplicate any information that is present in the
user manual.
# Roadmap / TODOs / open Ends
# Roadmap / TODOs / open ends
## Documentation
* the printf family of function does not completely implement all printf modifiers and does not behave as expected in some cases - all this should be documented in detail
* The printf() family of functions does not completely
implement all printf() modifiers and does not behave as
expected in some cases - all this should be documented in
detail.
## Compiler
* We need a way that makes it possible to feed arbitrary assembler code into the optimzer, so we can have proper tests for it
* We need a way that makes it possible to feed arbitrary
assembler code into the optimzer, so we can have proper
tests for it.
### Floating point support
The first step is implementing the datatype "float" as IEEE 754 floats. Help welcomed!
The first step is implementing the datatype "float" as IEEE
754 floats. Help welcomed!
* WIP compiler/library changes are here: https://github.com/cc65/cc65/pull/1777
* WIP compiler/library changes are here:
https://github.com/cc65/cc65/pull/1777
## Library
### name clashes in the library
see "Identifiers and Symbol names" above - not all identifiers have been checked
and renamed yet. The following is a list of those that still might need to be
fixed:
```
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
```
Some name clashes need to be resolved. Please see the
[detailed list of name clashes](libsrc/NameClashes.md).
## Test suite
* specific tests to check the optimizer (rather than the codegenerator) are needed.
* we need more specific tests to check standard conformance of the library headers
* Specific tests to check the optimizer (rather than the code
generator) are needed.
* We need more specific tests to check standard conformance
of the library headers.

View File

@ -1,21 +1,62 @@
# About cc65
The cc65 cross-compiler suite
=============================
cc65 is a complete cross development package for 65(C)02 systems, including
a powerful macro assembler, a C compiler, linker, archiver and several
other tools. cc65 has C and runtime library support for many of the old 6502 machines.
For details look at the [Website](https://cc65.github.io).
cc65 is a complete cross-development package for 65(C)02 systems,
including a powerful macro assembler, a C compiler, linker, archiver,
simulator and several other tools. cc65 has C and runtime library
support for many of the old 6502 machines. For details look at
the [cc65 web site](https://cc65.github.io):
| Company / People | Machine / Environment |
|-------------------------|-------------------------------------|
| Apple | Apple II |
| | Apple IIe enhanced |
| Atari | Atari 400/800 |
| | Atari 2600 |
| | Atari 5200 |
| | Atari 7800 |
| | Atari XL |
| | Lynx |
| Tangerine | Oric Atmos |
| Eureka | Oric Telestrat |
| Acorn | BBC series |
| Commodore | C128 |
| | C16 |
| | C64 |
| | CBM 510/610 |
| | PET |
| | Plus/4 |
| | VIC-20 |
| VTech | CreatiVision |
| Commander X16 Community | Commander X16 |
| Bit Corporation | Gamate |
| Berkeley Softworks | GEOS (Apple/CBM) |
| LUnix Team | LUnix (C64) |
| Nintendo | Nintendo Entertainment System (NES) |
| Ohio Scientific | OSI C1P |
| MOS Technology, Inc. | KIM-1 |
| NEC | PC Engine (PCE) |
| Dr. Jozo Dujmović | Picocomputer (RP6502) |
| Watara | Watura/QuickShot Supervision |
| Synertek | SYM-1 |
A generic configuration to adapt cc65 to new targets is also around.
## People
Project founders:
cc65 is originally based on the "Small C" compiler by Ron Cain and
enhanced by James E. Hendrix.
* John R. Dunning: [original implementation](https://public.websites.umich.edu/~archive/atari/8bit/Languages/Cc65/) of the C compiler and runtime library, Atari hosted
### Project founders
* John R. Dunning: [original implementation](https://public.websites.umich.edu/~archive/atari/8bit/Languages/Cc65/)
of the C compiler and runtime library, Atari hosted.
* Ullrich von Bassewitz:
* move the code to modern systems
* rewrite most parts of the compiler
* complete rewrite of the runtime library
* moved Dunning's code to modern systems,
* rewrote most parts of the compiler,
* rewrote all of the runtime library.
Core team members:
### Core team members
* [Christian Groessler](https://github.com/groessler): Atari, Atari5200, and CreatiVision library Maintainer
* [dqh](https://github.com/dqh-au): GHA help
@ -23,7 +64,7 @@ Core team members:
* [groepaz](https://github.com/mrdudz): CBM library, Project Maintainer
* [Oliver Schmidt](https://github.com/oliverschmidt): Apple II library Maintainer
External contributors:
### External contributors
* [acqn](https://github.com/acqn): various compiler fixes
* [jedeoric](https://github.com/jedeoric): Telestrat target
@ -36,28 +77,31 @@ External contributors:
*(The above list is incomplete, if you feel left out - please speak up or add yourself in a PR)*
For a complete list look at the [full team list](https://github.com/orgs/cc65/teams) or the list of [all contributors](https://github.com/cc65/cc65/graphs/contributors)
For a complete list look at the [full team list](https://github.com/orgs/cc65/teams)
or the list of [all contributors](https://github.com/cc65/cc65/graphs/contributors).
# Contact
For general discussion, questions, etc subscribe to the [mailing list](https://cc65.github.io/mailing-lists.html) or use the [github discussions](https://github.com/cc65/cc65/discussions).
For general discussion, questions, etc subscribe to the
[mailing list](https://cc65.github.io/mailing-lists.html)
or use the [github discussions](https://github.com/cc65/cc65/discussions).
Some of us may also be around on IRC [#cc65](https://web.libera.chat/#cc65) on libera.chat
Some of us may also be around on IRC [#cc65](https://web.libera.chat/#cc65) on libera.chat.
# Documentation
* The main [Documentation](https://cc65.github.io/doc) for users and developers
* Info on [Contributing](Contributing.md) to the CC65 project. Please read this before working on something you want to contribute, and before reporting bugs.
* The [Wiki](https://github.com/cc65/wiki/wiki) contains some extra info that does not fit into the regular documentation.
* The main [Documentation](https://cc65.github.io/doc) for users and
developers.
* Info on [Contributing](Contributing.md) to the CC65 project. Please
read this before working on something you want to contribute, and
before reporting bugs.
* The [Wiki](https://github.com/cc65/wiki/wiki) contains some extra info
that does not fit into the regular documentation.
# Downloads
* [Windows 64bit Snapshot](https://sourceforge.net/projects/cc65/files/cc65-snapshot-win64.zip)
* [Windows 32bit Snapshot](https://sourceforge.net/projects/cc65/files/cc65-snapshot-win32.zip)
* [Linux Snapshot DEB and RPM](https://software.opensuse.org/download.html?project=home%3Astrik&package=cc65)
[![Snapshot Build](https://github.com/cc65/cc65/actions/workflows/snapshot-on-push-master.yml/badge.svg?branch=master)](https://github.com/cc65/cc65/actions/workflows/snapshot-on-push-master.yml)

View File

@ -15,7 +15,7 @@ CPU_ISET_4510 = $0400
CPU_NONE = CPU_ISET_NONE
CPU_6502 = CPU_ISET_6502
CPU_6502X = CPU_ISET_6502|CPU_ISET_6502X
CPU_6502DTV = CPU_ISET_6502|CPU_ISET_6502X|CPU_ISET_6502DTV
CPU_6502DTV = CPU_ISET_6502|CPU_ISET_6502DTV
CPU_65SC02 = CPU_ISET_6502|CPU_ISET_65SC02
CPU_65C02 = CPU_ISET_6502|CPU_ISET_65SC02|CPU_ISET_65C02
CPU_65816 = CPU_ISET_6502|CPU_ISET_65SC02|CPU_ISET_65816

View File

@ -66,3 +66,9 @@
.global _clock_settime
.global _localtime
.global _mktime
;------------------------------------------------------------------------------
; Constants
CLOCK_REALTIME = 0

20
cfg/c16-asm.cfg Normal file
View File

@ -0,0 +1,20 @@
FEATURES {
STARTADDRESS: default = $1001;
}
SYMBOLS {
__LOADADDR__: type = import;
}
MEMORY {
ZP: file = "", start = $0002, size = $001A;
LOADADDR: file = %O, start = %S - 2, size = $0002;
MAIN: file = %O, start = %S, size = $3000 - %S;
}
SEGMENTS {
ZEROPAGE: load = ZP, type = zp, optional = yes;
LOADADDR: load = LOADADDR, type = ro;
EXEHDR: load = MAIN, type = ro, optional = yes;
CODE: load = MAIN, type = ro;
RODATA: load = MAIN, type = ro, optional = yes;
DATA: load = MAIN, type = rw, optional = yes;
BSS: load = MAIN, type = bss, define = yes;
}

20
cfg/plus4-asm.cfg Normal file
View File

@ -0,0 +1,20 @@
FEATURES {
STARTADDRESS: default = $1001;
}
SYMBOLS {
__LOADADDR__: type = import;
}
MEMORY {
ZP: file = "", start = $0002, size = $001A;
LOADADDR: file = %O, start = %S - 2, size = $0002;
MAIN: file = %O, start = %S, size = $FD00 - %S;
}
SEGMENTS {
ZEROPAGE: load = ZP, type = zp, optional = yes;
LOADADDR: load = LOADADDR, type = ro;
EXEHDR: load = MAIN, type = ro, optional = yes;
CODE: load = MAIN, type = ro;
RODATA: load = MAIN, type = ro, optional = yes;
DATA: load = MAIN, type = rw, optional = yes;
BSS: load = MAIN, type = bss, define = yes;
}

22
cfg/vic20-asm-32k.cfg Normal file
View File

@ -0,0 +1,22 @@
# Assembly program configuration for expanded VICs (>= +8K).
FEATURES {
STARTADDRESS: default = $1201;
}
SYMBOLS {
__LOADADDR__: type = import;
}
MEMORY {
ZP: file = "", start = $0002, size = $001A, define = yes;
LOADADDR: file = %O, start = %S - 2, size = $0002;
MAIN: file = %O, start = %S, size = $8000 - %S;
}
SEGMENTS {
ZEROPAGE: load = ZP, type = zp, optional = yes;
LOADADDR: load = LOADADDR, type = ro;
EXEHDR: load = MAIN, type = ro, optional = yes;
CODE: load = MAIN, type = ro;
RODATA: load = MAIN, type = ro;
DATA: load = MAIN, type = rw;
BSS: load = MAIN, type = bss, optional = yes, define = yes;
}

22
cfg/vic20-asm-3k.cfg Normal file
View File

@ -0,0 +1,22 @@
# Assembly program configuration for expanded VICs (+3K only).
FEATURES {
STARTADDRESS: default = $0401;
}
SYMBOLS {
__LOADADDR__: type = import;
}
MEMORY {
ZP: file = "", start = $0002, size = $001A, define = yes;
LOADADDR: file = %O, start = %S - 2, size = $0002;
MAIN: file = %O, start = %S, size = $1E00 - %S;
}
SEGMENTS {
ZEROPAGE: load = ZP, type = zp, optional = yes;
LOADADDR: load = LOADADDR, type = ro;
EXEHDR: load = MAIN, type = ro, optional = yes;
CODE: load = MAIN, type = ro;
RODATA: load = MAIN, type = ro;
DATA: load = MAIN, type = rw;
BSS: load = MAIN, type = bss, optional = yes, define = yes;
}

View File

@ -1,3 +1,5 @@
# Assembly program configuration for unexpanded VICs.
FEATURES {
STARTADDRESS: default = $1001;
}
@ -7,11 +9,12 @@ SYMBOLS {
MEMORY {
ZP: file = "", start = $0002, size = $001A, define = yes;
LOADADDR: file = %O, start = %S - 2, size = $0002;
MAIN: file = %O, start = %S, size = $0DF3 - %S;
MAIN: file = %O, start = %S, size = $1E00 - %S;
}
SEGMENTS {
ZEROPAGE: load = ZP, type = zp, optional = yes;
LOADADDR: load = LOADADDR, type = ro;
EXEHDR: load = MAIN, type = ro, optional = yes;
CODE: load = MAIN, type = ro;
RODATA: load = MAIN, type = ro;
DATA: load = MAIN, type = rw;

View File

@ -330,6 +330,7 @@ usage.
<item>_dos_type
<item>_filetype
<item>_datetime
<item>allow_lowercase
<item>beep
<item>get_ostype
<item>gmtime_dt
@ -452,10 +453,15 @@ The names in the parentheses denote the symbols to be used for static linking of
(RTS/CTS) and does interrupt driven receives. Speeds faster than 9600 baud
aren't reachable because the ROM and ProDOS IRQ handlers are too slow.
Software flow control (XON/XOFF) is not supported.
Note that because of the peculiarities of the 6551 chip transmits are not
interrupt driven, and the transceiver blocks if the receiver asserts
flow control because of a full buffer.
Note that using the driver at SER_BAUD_115200 will disable IRQs. It will be up
to the users to use the serial port, either by re-enabling IRQs themselves,
or by directly poll-reading the ACIA DATA register without the help of ser_get().
The driver defaults to slot 2. Call <tt/ser_apple2_slot()/ prior to
<tt/ser_open()/ in order to select a different slot. <tt/ser_apple2_slot()/
succeeds for all Apple&nbsp;II slots, but <tt/ser_open()/ fails with

View File

@ -453,10 +453,15 @@ The names in the parentheses denote the symbols to be used for static linking of
(RTS/CTS) and does interrupt driven receives. Speeds faster than 9600 baud
aren't reachable because the ROM and ProDOS IRQ handlers are too slow.
Software flow control (XON/XOFF) is not supported.
Note that because of the peculiarities of the 6551 chip transmits are not
interrupt driven, and the transceiver blocks if the receiver asserts
flow control because of a full buffer.
Note that using the driver at SER_BAUD_115200 will disable IRQs. It will be up
to the users to use the serial port, either by re-enabling IRQs themselves,
or by directly poll-reading the ACIA DATA register without the help of ser_get().
The driver defaults to slot 2. Call <tt/ser_apple2_slot()/ prior to
<tt/ser_open()/ in order to select a different slot. <tt/ser_apple2_slot()/
succeeds for all Apple&nbsp;II slots, but <tt/ser_open()/ fails with

View File

@ -1,15 +1,15 @@
<!doctype linuxdoc system>
<article>
<title>Oric Atmos-specific information for cc65
<title>Tangerine Oric Atmos-specific information for cc65
<author>
<url url="mailto:uz@cc65.org" name="Ullrich von Bassewitz">,<newline>
<url url="mailto:polluks@sdf.lonestar.org" name="Stefan A. Haubenthal">,<newline>
<url url="mailto:polluks@sdf.org" name="Stefan A. Haubenthal">,<newline>
<url url="mailto:greg.king5@verizon.net" name="Greg King">
<abstract>
An overview over the Atmos runtime system as it is implemented for the cc65 C
compiler.
An overview over the Oric Atmos runtime system as it is implemented for the cc65
C compiler. This target is not Oric-1 compatible.
</abstract>
<!-- Table of contents -->

View File

@ -829,49 +829,42 @@ names like "Loop". Here is an example:
bne @Loop ; ERROR: Unknown identifier!
</verb></tscreen>
<sect1>Unnamed labels<p>
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 <tt>@:</tt> (<tt>.LOCALCHAR</tt> is respected if it
is set) or sole <tt>:</tt>.
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 <tt>@</tt> (<tt>.LOCALCHAR</tt> is respected
if it is set) or <tt>:</tt> with several <tt>-</tt> or <tt>+</tt> characters.
The <tt>-</tt> characters will create a back reference (n'th label backwards),
the <tt>+</tt> will create a forward reference (n'th label in forward direction).
As an alternative, angle brackets <tt>&lt;</tt> and <tt>&gt;</tt> may be used
instead of <tt>-</tt> and <tt>+</tt> with the same meaning.
Example:
<tscreen><verb>
: 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
</verb></tscreen>
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.
<em/Note:/ <ref id="scopes" name="Scopes"> organize named symbols, not
unnamed ones, so scopes don't have an effect on unnamed labels.
<sect1>Using macros to define labels and constants<p>
While there are drawbacks with this approach, it may be handy in a few rare

View File

@ -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.
<p>
<item> In <tt/cc65/ mode, <tt/main()/ cannot be called recursively. If this
is necessary, the program must be compiled in <tt/c89/ or <tt/c99/ mode
using the <tt><ref id="option--standard" name="--standard"></tt>
command line option.
<p>
</itemize>
There may be some more minor differences I'm currently not aware of. The
@ -1273,6 +1279,12 @@ If the first parameter is <tt/push/, the old value is saved onto a stack
before changing it. The value may later be restored by using the <tt/pop/
parameter with the <tt/#pragma/.
For all pragma names that contain hyphens, the same name using underlines
instead of the hyphens is available as an alternative. While the former
resembles the corresponding command line option and is more orthogonal, the
latter may be more compatible with external tools that rewrite the token
sequences of the input.
<sect1><tt>#pragma allow-eager-inline ([push,] on|off)</tt><label id="pragma-allow-eager-inline"><p>

View File

@ -243,6 +243,12 @@ point to <tt/cx320p1.tgi (cx320p1_tgi)/.
a way that's compatible with some of the other color drivers).
</descrip><p>
<descrip>
<tag><tt/cx640p1.tgi (cx640p1_tgi)/</tag>
This driver features a resolution of 640 across and 480 down with 2 colors,
black and white.
</descrip><p>
<sect1>Extended memory drivers<p>

View File

@ -95,6 +95,7 @@ function.
<itemize>
<item>_dos_type
<item>allow_lowercase
<item><ref id="beep" name="beep">
<item><ref id="get_ostype" name="get_ostype">
<item><ref id="gmtime_dt" name="gmtime_dt">
@ -154,6 +155,7 @@ function.
<item><ref id="atmos_tick" name="atmos_tick">
<item><ref id="atmos_tock" name="atmos_tock">
<item><ref id="atmos_zap" name="atmos_zap">
<item><ref id="waitvsync" name="waitvsync">
</itemize>
@ -780,6 +782,7 @@ communication, see also <tt>testcode/lib/ser-test.c</tt>.
<item><ref id="strqtok" name="strqtok">
<item><ref id="strrchr" name="strrchr">
<item><ref id="strspn" name="strspn">
<item><ref id="strcasestr" name="strcasestr">
<item><ref id="strstr" name="strstr">
<item><ref id="strtok" name="strtok">
<item><ref id="strxfrm" name="strxfrm">
@ -7899,22 +7902,47 @@ be used in presence of a prototype.
</quote>
<sect1>strstr<label id="strstr"><p>
<sect1>strcasestr<label id="strcasestr"><p>
<quote>
<descrip>
<tag/Function/Find a substring.
<tag/Function/Find a substring, case-insensitive.
<tag/Header/<tt/<ref id="string.h" name="string.h">/
<tag/Declaration/<tt/char* __fastcall__ strstr (const char* str, const char* substr);/
<tag/Description/<tt/strstr/ searches for the first occurrence of the string
<tt/substr/ within <tt/str/. If found, it returns a pointer to the copy,
otherwise it returns <tt/NULL/.
<tag/Declaration/<tt/char* __fastcall__ strcasestr (const char* str, const char* substr);/
<tag/Description/<tt/strcasestr/ searches for the first occurrence of the string
<tt/substr/ within <tt/str/. If found, it returns a pointer to the start of the
match in <tt/str/, otherwise it returns <tt/NULL/.
<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
<tag/Availability/ISO 9899
<tag/See also/
<ref id="strstr" name="strstr">,
<ref id="strcspn" name="strcspn">,
<ref id="strspn" name="strspn">
<tag/Example/None.
</descrip>
</quote>
<sect1>strstr<label id="strstr"><p>
<quote>
<descrip>
<tag/Function/Find a substring, case-sensitive.
<tag/Header/<tt/<ref id="string.h" name="string.h">/
<tag/Declaration/<tt/char* __fastcall__ strstr (const char* str, const char* substr);/
<tag/Description/<tt/strstr/ searches for the first occurrence of the string
<tt/substr/ within <tt/str/. If found, it returns a pointer to the start of the
match in <tt/str/, otherwise it returns <tt/NULL/.
<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
<tag/Availability/ISO 9899
<tag/See also/
<ref id="strcasestr" name="strcasestr">,
<ref id="strcspn" name="strcspn">,
<ref id="strspn" name="strspn">
<tag/Example/None.
@ -8331,6 +8359,7 @@ only in the presence of a prototype.
<descrip>
<tag/Function/Wait until the start of the next video frame.
<tag/Header/<tt/
<ref id="atmos.h" name="atmos.h">,
<ref id="cbm.h" name="cbm.h">,
<ref id="gamate.h" name="gamate.h">,
<ref id="nes.h" name="nes.h">,
@ -8338,6 +8367,7 @@ only in the presence of a prototype.
<tag/Declaration/<tt/void waitvsync (void);/
<tag/Description/Wait for vertical sync, to reduce flickering.
<tag/Availability/Platforms served by the headers above
(Atmos requires the VSync hack)
<tag/Example/None.
</descrip>
</quote>

View File

@ -115,37 +115,78 @@ PVExit ($01)
<sect>Creating a Test in C<p>
For a C test compiled and linked with <tt/--target sim6502/ the
For a C test linked with <tt/--target sim6502/ and the <tt/sim6502.lib/ library,
command line arguments to <tt/sim65/ will be passed to <tt/main/,
and the return value from <tt/main/ will become sim65's exit code.
The <tt/exit/ function may also be used to terminate with an exit code.
The <tt/stdlib.h/ <tt/exit/ function may also be used to terminate with an exit code.
Exit codes are limited to 8 bits.
Exit codes are limited to an unsigned 8 bit value. (E.g. returning -1 will give an exit code of 255.)
The standard C library high level file input and output is functional.
A sim65 application can be written like a command line application,
providing arguments to <tt/main/ and using the <tt/stdio.h/ interfaces.
providing command line arguments to <tt/main/ and using the <tt/stdio.h/ interfaces
to interact with the console or access files.
Internally, file input and output is provided at a lower level by
a set of built-in paravirtualization functions (<ref id="paravirt-internal" name="see below">).
a set of built-in paravirtualization functions (see <ref id="paravirt-internal" name="below">).
Example:
<tscreen><verb>
#include <stdio.h>
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
</verb></tscreen>
<sect>Creating a Test in Assembly<p>
Assembly tests may similarly be assembled and linked with
<tt/--target sim6502/ or <tt/--target sim65c02/.
Define and export <tt/_main/ as an entry point,
Though a C test may also link with assembly code,
a pure assembly test can also be created.
Link with <tt/--target sim6502/ or <tt/--target sim65c02/ and the corresponding library,
define and export <tt/_main/ as an entry point,
and the sim65 library provides two ways to return an 8-bit exit code:
<itemize>
<item>Return from <tt/_main/ with the exit code in <tt/A/.
<item><tt/jmp exit/ with the code in <tt/A/.
<item><tt/jmp exit/ with the code in <tt/A/. (<tt/.import exit/ from the sim65 library.)
</itemize>
The binary file has a 12 byte header:
Example:
<tscreen><verb>
.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
</verb></tscreen>
Internally, the binary program file has a 12 byte header provided by the library:
<itemize>
@ -182,6 +223,9 @@ These use cc65 calling conventions, and are intended for use with the sim65 targ
<item><tt/IRQ/ and <tt/NMI/ events will not be generated, though <tt/BRK/
can be used if the IRQ vector at <tt/$FFFE/ is manually prepared by the test code.
<item>The <tt/sim6502/ or <tt/sim65c02/ targets provide a default configuration,
but if customization is needed <tt/sim6502.cfg/ or <tt/sim65c02.cfg/ might be used as a template.
</itemize>

View File

@ -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 */

View File

@ -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 */
/*****************************************************************************/

View File

@ -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

View File

@ -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)

View File

@ -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 */

View File

@ -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

View File

@ -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);

380
libsrc/NameClashes.md Normal file
View File

@ -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

View File

@ -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

75
libsrc/apple2/callmain.s Normal file
View File

@ -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
lda #>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

View File

@ -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:

View File

@ -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
lda #>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
; ------------------------------------------------------------------------

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,9 @@
;
; Oliver Schmidt, 2024-08-06
;
.export uppercasemask
.data
uppercasemask: .byte $DF ; Convert to uppercase

View File

@ -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

View File

@ -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

18
libsrc/atmos/waitvsync.s Normal file
View File

@ -0,0 +1,18 @@
;
; Written by Stefan Haubenthal <polluks@sdf.org>, requires VSync hack
;
; void waitvsync (void);
;
.export _waitvsync
.include "atmos.inc"
.proc _waitvsync
lda #%00010000 ; CB1
wait: and VIA::PRA2
bne wait
rts
.endproc

View File

@ -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

22
libsrc/common/stpcpy.s Normal file
View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -82,14 +82,3 @@ _strstr:
lda #$00 ; return NULL
tax
rts

View File

@ -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
ldx #>time
jsr _clock_gettime
sta tmp2
lda #<time
ldx #>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

View File

@ -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

675
libsrc/cx16/tgi/cx640p1.s Normal file
View File

@ -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
ldx #>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
ldx #>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"

View File

@ -9,8 +9,7 @@
.include "pet.inc"
_waitvsync:
@l1:
lda VIA_PB
and #%00100000
bne @l1
lda #%00100000
: and VIA_PB
bne :-
rts

View File

@ -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

View File

@ -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

15
samples/cbm/hello-asm.s Normal file
View File

@ -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!"

View File

@ -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:

View File

@ -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;
}

View File

@ -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 */

View File

@ -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.
*/

View File

@ -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;
}

View File

@ -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, /* <> */

View File

@ -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) {

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

File diff suppressed because it is too large Load Diff

View File

@ -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);

View File

@ -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 ();

View File

@ -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);

View File

@ -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 */

View File

@ -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"

View File

@ -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;

View File

@ -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);

View File

@ -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 <filename> */
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 <h-char-sequence> 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 <filename> */
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);

View File

@ -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 ();

View File

@ -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;
}
}
}

View File

@ -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;

View File

@ -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);
}

File diff suppressed because it is too large Load Diff

View File

@ -47,7 +47,8 @@
/* Supported CPUs */
typedef enum CPUType {
CPU_6502,
CPU_65C02
CPU_65C02,
CPU_6502X
} CPUType;
/* Current CPU */

View File

@ -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 */

View File

@ -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);

View File

@ -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) {

View File

@ -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();

View File

@ -14,7 +14,9 @@ WORKDIR = ../testwrk
.PHONY: test continue mostlyclean clean
test: mostlyclean continue
test:
@$(MAKE) mostlyclean
@$(MAKE) continue
continue:
@$(MAKE) -C asm all

View File

@ -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))

View File

@ -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

View File

@ -0,0 +1 @@
foo:

View File

@ -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

View File

@ -0,0 +1 @@
.out "include file"

View File

@ -0,0 +1,4 @@
.repeat 3
.include "070-include-repeat.inc"
.out "main file"
.endrepeat

View File

@ -0,0 +1 @@
bar::foo is defined

View File

@ -0,0 +1,6 @@
include file
main file
include file
main file
include file
main file

View File

@ -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)

4
test/misc/bug2515.c Normal file
View File

@ -0,0 +1,4 @@
#line 13"x"
#define X"y"
int main() { foo; }

View File

@ -0,0 +1,2 @@
x:13: Warning: ISO C99 requires whitespace after the macro name
x:14: Error: Undeclared identifier 'foo'

1
test/misc/bug2515.ref Normal file
View File

@ -0,0 +1 @@
x:14: Error: Undeclared identifier 'foo'

View File

@ -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

3
test/ref/bug2134.c Normal file
View File

@ -0,0 +1,3 @@
int i = { 0 };
char* p = { 0 };
int main() { return 0; }

2
test/ref/bug2134.cref Normal file
View File

@ -0,0 +1,2 @@
bug2134.c:1: Warning: Braces around scalar initializer
bug2134.c:2: Warning: Braces around scalar initializer

View File

@ -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 */

167
test/standard/stdint.c Normal file
View File

@ -0,0 +1,167 @@
/* Test definitions from stdint.h */
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
#include <limits.h>
#include <signal.h>
/* 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;
}

10
test/val/bug2458.c Normal file
View File

@ -0,0 +1,10 @@
#define str(arg) #arg
#include str(bug2458.h) /* Ok, macro replacement */
#define string foo
#include <string.h> /* Ok, no macro replacement */
int main()
{
return 0;
}

1
test/val/bug2458.h Normal file
View File

@ -0,0 +1 @@

Some files were not shown because too many files have changed in this diff Show More