1
0
mirror of https://github.com/cc65/cc65.git synced 2024-06-08 15:29:37 +00:00

Merge branch 'master' into fptest

This commit is contained in:
mrdudz 2023-10-14 18:44:19 +02:00
commit db7a38ea17
89 changed files with 2011 additions and 426 deletions

15
.editorconfig Normal file
View File

@ -0,0 +1,15 @@
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 4
trim_trailing_whitespace = true
insert_final_newline = true
guidelines = 80, 120
[*.{c,h}]
cpp_new_line_before_open_brace_block=same_line
cpp_new_line_before_open_brace_function=new_line
cpp_space_before_function_open_parenthesis=insert
cpp_new_line_before_else=false

View File

@ -139,7 +139,7 @@ You can refer to Annex B of the ISO C99 standard ([here](https://www.open-std.or
* 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>
lda #RETURN_VALUE
ldx #0 ; return value is char
ldx #0 ; Promote char return value
</pre>
or, if the value is 0, you can use:
<pre>

View File

@ -7,6 +7,10 @@ For details look at the [Website](https://cc65.github.io).
## People
Project founder:
* Ullrich von Bassewitz
Core team members:
* [Christian Groessler](https://github.com/groessler): Atari, Atari5200, and CreatiVision library Maintainer

View File

@ -27,7 +27,7 @@ SEGMENTS {
CODE: load = MAIN, type = ro start = $4000;
RODATA: load = MAIN, type = ro;
DATA: load = MAIN, type = rw;
INIT: load = MAIN, type = rw;
INIT: load = MAIN, type = rw; # uninitialized, but reserves output space
ONCE: load = MAIN, type = ro, define = yes;
LC: load = MAIN, run = LC, type = ro, optional = yes;
BSS: load = BSS, type = bss, define = yes;

View File

@ -43,7 +43,7 @@ SEGMENTS {
CODE: load = MAIN, type = ro;
RODATA: load = MAIN, type = ro;
DATA: load = MAIN, type = rw;
INIT: load = MAIN, type = rw;
INIT: load = MAIN, type = rw; # uninitialized, but reserves output space
ONCE: load = MAIN, type = ro, define = yes;
LC: load = MAIN, run = LC, type = ro, optional = yes;
BSS: load = BSS, type = bss, define = yes;

View File

@ -22,7 +22,7 @@ SEGMENTS {
CODE: load = MAIN, type = ro;
RODATA: load = MAIN, type = ro;
DATA: load = MAIN, type = rw;
INIT: load = MAIN, type = rw;
INIT: load = MAIN, type = rw; # uninitialized, but reserves output space
ONCE: load = MAIN, type = ro, define = yes;
LC: load = MAIN, run = LC, type = ro, optional = yes;
BSS: load = BSS, type = bss, define = yes;

View File

@ -26,7 +26,7 @@ SEGMENTS {
CODE: load = MAIN, type = ro;
RODATA: load = MAIN, type = ro;
DATA: load = MAIN, type = rw;
INIT: load = MAIN, type = rw;
INIT: load = MAIN, type = rw; # uninitialized, but reserves output space
ONCE: load = MAIN, type = ro, define = yes;
LC: load = MAIN, run = LC, type = ro, optional = yes;
BSS: load = BSS, type = bss, define = yes;

View File

@ -27,7 +27,7 @@ SEGMENTS {
CODE: load = MAIN, type = ro start = $4000;
RODATA: load = MAIN, type = ro;
DATA: load = MAIN, type = rw;
INIT: load = MAIN, type = rw;
INIT: load = MAIN, type = rw; # uninitialized, but reserves output space
ONCE: load = MAIN, type = ro, define = yes;
LC: load = MAIN, run = LC, type = ro, optional = yes;
BSS: load = BSS, type = bss, define = yes;

View File

@ -43,7 +43,7 @@ SEGMENTS {
CODE: load = MAIN, type = ro;
RODATA: load = MAIN, type = ro;
DATA: load = MAIN, type = rw;
INIT: load = MAIN, type = rw;
INIT: load = MAIN, type = rw; # uninitialized, but reserves output space
ONCE: load = MAIN, type = ro, define = yes;
LC: load = MAIN, run = LC, type = ro, optional = yes;
BSS: load = BSS, type = bss, define = yes;

View File

@ -22,7 +22,7 @@ SEGMENTS {
CODE: load = MAIN, type = ro;
RODATA: load = MAIN, type = ro;
DATA: load = MAIN, type = rw;
INIT: load = MAIN, type = rw;
INIT: load = MAIN, type = rw; # uninitialized, but reserves output space
ONCE: load = MAIN, type = ro, define = yes;
LC: load = MAIN, run = LC, type = ro, optional = yes;
BSS: load = BSS, type = bss, define = yes;

View File

@ -26,7 +26,7 @@ SEGMENTS {
CODE: load = MAIN, type = ro;
RODATA: load = MAIN, type = ro;
DATA: load = MAIN, type = rw;
INIT: load = MAIN, type = rw;
INIT: load = MAIN, type = rw; # uninitialized, but reserves output space
ONCE: load = MAIN, type = ro, define = yes;
LC: load = MAIN, run = LC, type = ro, optional = yes;
BSS: load = BSS, type = bss, define = yes;

View File

@ -52,7 +52,7 @@ SEGMENTS {
CODE: load = MAIN, type = ro, define = yes;
RODATA: load = MAIN, type = ro;
DATA: load = MAIN, type = rw;
INIT: load = MAIN, type = rw, optional = yes;
INIT: load = MAIN, type = bss, optional = yes;
BSS: load = MAIN, type = bss, define = yes;
AUTOSTRT: load = TRAILER, type = ro;
OVERLAY1: load = OVL1, type = ro, define = yes, optional = yes;

View File

@ -36,7 +36,7 @@ SEGMENTS {
CODE: load = MAIN, type = ro, define = yes;
RODATA: load = MAIN, type = ro;
DATA: load = MAIN, type = rw;
INIT: load = MAIN, type = rw, optional = yes;
INIT: load = MAIN, type = bss, optional = yes;
BSS: load = MAIN, type = bss, define = yes;
}
FEATURES {

View File

@ -40,7 +40,7 @@ SEGMENTS {
CODE: load = MAIN, type = ro, define = yes;
RODATA: load = MAIN, type = ro;
DATA: load = MAIN, type = rw;
INIT: load = MAIN, type = rw, optional = yes;
INIT: load = MAIN, type = bss, optional = yes;
BSS: load = MAIN, type = bss, define = yes;
AUTOSTRT: load = TRAILER, type = ro;
}

View File

@ -67,7 +67,7 @@ SEGMENTS {
CODE: load = MAIN, type = ro, define = yes;
RODATA: load = MAIN, type = ro;
DATA: load = MAIN, type = rw;
INIT: load = MAIN, type = rw, optional = yes;
INIT: load = MAIN, type = bss, optional = yes;
BSS: load = MAIN, type = bss, define = yes;
AUTOSTRT: load = TRAILER, type = ro;
}

View File

@ -78,7 +78,7 @@ SEGMENTS {
CODE: load = MAIN, type = ro, define = yes;
RODATA: load = MAIN, type = ro;
DATA: load = MAIN, type = rw;
INIT: load = MAIN, type = rw, optional = yes;
INIT: load = MAIN, type = bss, optional = yes;
BSS: load = MAIN, type = bss, define = yes;
AUTOSTRT: load = TRAILER, type = ro;

View File

@ -58,7 +58,7 @@ SEGMENTS {
CODE: load = MAIN, type = ro, define = yes;
RODATA: load = MAIN, type = ro;
DATA: load = MAIN, type = rw;
INIT: load = MAIN, type = rw, optional = yes;
INIT: load = MAIN, type = bss, optional = yes;
BSS: load = MAIN, type = bss, define = yes;
SRPREPHDR: load = UNUSED, type = ro;
SRPREPTRL: load = UNUSED, type = ro;

View File

@ -65,7 +65,7 @@ SEGMENTS {
CODE: load = MAIN, type = ro, define = yes;
RODATA: load = MAIN, type = ro;
DATA: load = MAIN, type = rw;
INIT: load = MAIN, type = rw, optional = yes;
INIT: load = MAIN, type = bss, optional = yes;
BSS: load = MAIN, type = bss, define = yes;
AUTOSTRT: load = TRAILER, type = ro;
}

View File

@ -23,7 +23,7 @@ SEGMENTS {
CODE: load = MAIN, type = ro;
RODATA: load = MAIN, type = ro;
DATA: load = MAIN, type = rw;
INIT: load = MAIN, type = rw;
INIT: load = MAIN, type = rw; # uninitialized, but reserves output space
ONCE: load = MAIN, type = ro, define = yes;
BASTAIL: load = MAIN, type = ro, optional = yes;
BSS: load = BSS, type = bss, define = yes;

View File

@ -44,7 +44,7 @@ SEGMENTS {
CODE: load = MAIN, type = ro;
RODATA: load = MAIN, type = ro;
DATA: load = MAIN, type = rw;
INIT: load = MAIN, type = rw;
INIT: load = MAIN, type = rw; # uninitialized, but reserves output space
ONCE: load = MAIN, type = ro, define = yes;
BSS: load = BSS, type = bss, define = yes;
OVL1ADDR: load = OVL1ADDR, type = ro;

View File

@ -23,7 +23,7 @@ SEGMENTS {
CODE: load = MAIN, type = ro;
RODATA: load = MAIN, type = ro;
DATA: load = MAIN, type = rw;
INIT: load = MAIN, type = rw;
INIT: load = MAIN, type = rw; # uninitialized, but reserves output space
ONCE: load = MAIN, type = ro, define = yes;
BSS: load = BSS, type = bss, define = yes;
}

View File

@ -11,10 +11,10 @@ SEGMENTS {
ZP: load = ZP, type = zp, optional = yes;
VECTORS: load = ROM, run = RAM, type = rw, define = yes;
DATA: load = ROM, run = RAM, type = rw, define = yes, start = $0204;
INIT: load = RAM, type = bss, optional = yes;
BSS: load = RAM, type = bss, define = yes;
ONCE: load = ROM, type = ro, optional = yes;
CODE: load = ROM, type = ro;
INIT: load = ROM, type = ro;
RODATA: load = ROM, type = ro;
AUDIO: load = ROM, type = ro, optional = yes, start = $BF00;
SETUP: load = ROM, type = ro, start = $BFE8;

View File

@ -57,7 +57,7 @@ SEGMENTS {
CODE: load = MAIN, type = ro;
RODATA: load = MAIN, type = ro;
DATA: load = MAIN, type = rw;
INIT: load = MAIN, type = rw, optional = yes;
INIT: load = MAIN, type = rw, optional = yes; # uninitialized, but reserves output space
ONCE: load = MAIN, type = ro, define = yes;
BSS: load = BSS, type = bss, define = yes;
BRAM01ADDR: load = BRAM01ADDR, type = ro, optional = yes;

View File

@ -24,7 +24,7 @@ SEGMENTS {
CODE: load = MAIN, type = ro;
RODATA: load = MAIN, type = ro;
DATA: load = MAIN, type = rw;
INIT: load = MAIN, type = rw, optional = yes;
INIT: load = MAIN, type = rw, optional = yes; # uninitialized, but reserves output space
ONCE: load = MAIN, type = ro, define = yes;
BSS: load = BSS, type = bss, define = yes;
}

View File

@ -22,7 +22,7 @@ SEGMENTS {
CODE: load = MAIN, type = ro;
RODATA: load = MAIN, type = ro;
DATA: load = MAIN, type = rw;
INIT: load = MAIN, type = rw;
INIT: load = MAIN, type = rw; # uninitialized, but reserves output space
ONCE: load = MAIN, type = ro, define = yes;
BASTAIL: load = MAIN, type = ro, optional = yes;
BSS: load = BSS, type = bss, define = yes;

View File

@ -427,8 +427,12 @@ The names in the parentheses denote the symbols to be used for static linking of
<descrip>
<tag><tt/a2.ssc.ser (a2_ssc_ser)/</tag>
Driver for the Apple&nbsp;II Super Serial Card. Supports up to 19200 baud,
requires hardware flow control (RTS/CTS) and does interrupt driven receives.
Driver for the Apple&nbsp;II Super Serial Card.
The SSC is an extension card for the II, II+, IIe; the Apple //c and //c+ have
the same hardware and firmware integrated.
It supports up to 9600 baud, requires hardware flow control (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.
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.
@ -438,6 +442,25 @@ The names in the parentheses denote the symbols to be used for static linking of
succeeds for all Apple&nbsp;II slots, but <tt/ser_open()/ fails with
<tt/SER_ERR_NO_DEVICE/ if there's no SSC firmware found in the selected slot.
In the Apple //c and //c+, slot 1 is the printer port, and slot 2 is the modem
port.
Never call <tt/ser_apple2_slot()/ after <tt/ser_open()/.
<tag><tt/a2.gs.ser (a2_gs_ser)/</tag>
Driver for the Apple&nbsp;IIgs serial ports (printer and modem).
It supports up to 9600 baud, requires hardware flow control (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.
Note that transmits are not interrupt driven, and the transceiver blocks if
the receiver asserts flow control because of a full buffer.
The driver defaults to opening the modem port. Calling <tt/ser_apple2_slot()/
prior to <tt/ser_open()/ allows to select the printer port (1) or the modem
port (0).
Never call <tt/ser_apple2_slot()/ after <tt/ser_open()/.
</descrip><p>
@ -603,7 +626,7 @@ url="ca65.html" name="assembler manual">.
The header file <tt/apple2_filetype.h/ also defines many values
that can be used to set these variables. It is included in
<tt/apple2.h/, which is in turn included in <tt/apple2enh.h/.
<tt/apple2.h/.
<tag>Example</tag>

View File

@ -21,7 +21,8 @@ as it comes with the cc65 C compiler. It describes the memory layout,
enhanced&nbsp;Apple&nbsp;//e specific header files, available drivers, and any
pitfalls specific to that platform.
Please note that enhanced&nbsp;Apple&nbsp;//e specific functions are just mentioned
Please note that this target requires a 65C02 or 65816 CPU,
enhanced&nbsp;Apple&nbsp;//e specific functions are just mentioned
here, they are described in detail in the separate <url url="funcref.html"
name="function reference">. Even functions marked as "platform dependent" may
be available on more than one platform. Please see the function reference for
@ -427,8 +428,12 @@ The names in the parentheses denote the symbols to be used for static linking of
<descrip>
<tag><tt/a2e.ssc.ser (a2e_ssc_ser)/</tag>
Driver for the Apple&nbsp;II Super Serial Card. Supports up to 19200 baud,
requires hardware flow control (RTS/CTS) and does interrupt driven receives.
Driver for the Apple&nbsp;II Super Serial Card.
The SSC is an extension card for the II, II+, IIe; the Apple //c and //c+ have
the same hardware and firmware integrated.
It supports up to 9600 baud, requires hardware flow control (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.
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.
@ -438,6 +443,25 @@ The names in the parentheses denote the symbols to be used for static linking of
succeeds for all Apple&nbsp;II slots, but <tt/ser_open()/ fails with
<tt/SER_ERR_NO_DEVICE/ if there's no SSC firmware found in the selected slot.
In the Apple //c and //c+, slot 1 is the printer port, and slot 2 is the modem
port.
Never call <tt/ser_apple2_slot()/ after <tt/ser_open()/.
<tag><tt/a2e.gs.ser (a2e_gs_ser)/</tag>
Driver for the Apple&nbsp;IIgs serial ports (printer and modem).
It supports up to 9600 baud, requires hardware flow control (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.
Note that transmits are not interrupt driven, and the transceiver blocks if
the receiver asserts flow control because of a full buffer.
The driver defaults to opening the modem port. Calling <tt/ser_apple2_slot()/
prior to <tt/ser_open()/ allows to select the printer port (1) or the modem
port (0).
Never call <tt/ser_apple2_slot()/ after <tt/ser_open()/.
</descrip><p>

View File

@ -120,7 +120,7 @@ Long options:
--list-bytes n Maximum number of bytes per listing line
--memory-model model Set the memory model
--pagelength n Set the page length for the listing
--relax-checks Relax some checks (see docs)
--relax-checks Disables some error checks
--smart Enable smart mode
--target sys Set the target system
--verbose Increase verbosity
@ -265,14 +265,17 @@ Here is a description of all the command line options:
<label id="option--relax-checks">
<tag><tt>--relax-checks</tt></tag>
Relax some checks done by the assembler. This will allow code that is an
Disables some error checks done by the assembler. This will allow code that is an
error in most cases and flagged as such by the assembler, but can be valid
in special situations.
Examples are:
Disabled checks are:
<itemize>
<item>Short branches between two different segments.
<item>Byte sized address loads where the address is not a zeropage address.
<item>Address vs. fragment size: a byte sized load from an non-zeropage
address is truncated instead of producing an error.
<item>Indirect jump on page boundary: <tt>jmp (label)</tt> on a label that
resides on a page boundary (<tt>$xxFF</tt>) fetches the second byte from the
wrong address on 6502 CPUs, now allowed instead of producing an error.
</itemize>

View File

@ -837,7 +837,7 @@ This cc65 version has some extensions to the ISO C standard.
<itemize>
<item> The compiler allows to insert assembler statements into the output
<item> The compiler allows to insert assembler expressions into the output
file. The syntax is
<tscreen><verb>
@ -851,7 +851,7 @@ This cc65 version has some extensions to the ISO C standard.
The first form is in the user namespace; and, is disabled if the <tt/-A/
switch is given.
There is a whole section covering inline assembler statements,
There is a whole section covering inline assembler expressions,
<ref id="inline-asm" name="see there">.
<p>
@ -1714,7 +1714,7 @@ bloated code and a slowdown.
<sect>Inline assembler<label id="inline-asm"><p>
The compiler allows to insert assembler statements into the output file. The
The compiler allows to insert assembler expressions into the output file. The
syntax is
<tscreen><verb>
@ -1729,7 +1729,7 @@ or
The first form is in the user namespace; and, is disabled by <tt><ref
id="option--standard" name="--standard"></tt> if the argument is not <tt/cc65/.
The <tt/asm/ statement can be used only inside a function. Please note that
The <tt/asm/ expression can be used only inside a function. Please note that
the result of an inline assembler expression is always of type <tt/void/.
The contents of the string literal are preparsed by the compiler; and, inserted
@ -1741,15 +1741,15 @@ even if the ca65 assembler (which is used to translate the generated assembler
code) would accept them. The built-in inline assembler is not a replacement for
the full-blown macro assembler which comes with the compiler.
Note: Inline assembler statements are subject to all optimizations done by the
compiler. There currently is no way to protect an inline assembler statement
Note: Inline assembler expressions are subject to all optimizations done by the
compiler. There currently is no way to protect an inline assembler expression
-- alone -- from being moved or removed completely by the optimizer. If in
doubt, check the generated assembler output; or, disable optimizations (for
that function).
As a shortcut, you can put the <tt/volatile/ qualifier in your <tt/asm/
statements. It will disable optimization for the functions in which those
<tt/asm volatile/ statements sit. The effect is the same as though you put
expressions. It will disable optimization for the functions in which those
<tt/asm volatile/ expressions sit. The effect is the same as though you put
<tt/#pragma optimize(push, off)/ above those functions, and <tt/#pragma
optimize(pop)/ below those functions.
@ -1844,7 +1844,7 @@ Arrays also can be accessed:
<p>
Note: Do not embed the assembler labels that are used as names of global
variables or functions into your <tt/asm/ statements. Code such as this:
variables or functions into your <tt/asm/ expressions. Code such as this:
<tscreen><verb>
int foo;

View File

@ -334,9 +334,11 @@ function.
<itemize>
<!-- <item><ref id="get_numbanks" name="get_numbanks"> -->
<!-- <item><ref id="get_ostype" name="get_ostype"> -->
<item><ref id="get_ostype" name="get_ostype">
<!-- <item><ref id="get_tv" name="get_tv"> -->
<!-- <item><ref id="set_tv" name="set_tv"> -->
<!-- <item><ref id="vera_layer_enable" name="vera_layer_enable"> -->
<!-- <item><ref id="vera_sprites_enable" name="vera_sprites_enable"> -->
<item><ref id="videomode" name="videomode">
<!-- <item><ref id="vpeek" name="vpeek"> -->
<!-- <item><ref id="vpoke" name="vpoke"> -->
@ -440,6 +442,16 @@ see also <tt>testcode/lib/em-test.c</tt> and <tt>samples/multidemo.c</tt>.
<url url="geos.html" name="GEOS API">.
<sect1><tt/inet.h/<label id="inet.h"><p>
<itemize>
<item><ref id="htonl" name="htonl">
<item><ref id="htons" name="htons">
<item><ref id="ntohl" name="ntohl">
<item><ref id="ntohs" name="ntohs">
</itemize>
<sect1><tt/joystick.h/<label id="joystick.h"><p>
<itemize>
@ -452,6 +464,18 @@ see also <tt>testcode/lib/em-test.c</tt> and <tt>samples/multidemo.c</tt>.
</itemize>
<sect1><tt/kim1.h/<label id="kim1.h"><p>
<itemize>
<!-- <item><ref id="getkey" name="getkey"> -->
<!-- <item><ref id="scandisplay" name="scandisplay"> -->
<item><ref id="loadt" name="loadt">
<item><ref id="dumpt" name="dumpt">
</itemize>
(incomplete)
<sect1><tt/locale.h/<label id="locale.h"><p>
<itemize>
@ -1735,7 +1759,7 @@ used in presence of a prototype.
<tag/See also/
<ref id="fdisp" name="fdisp">,
<ref id="loadt" name="loadt">,
<ref id="dumpt" name="dumpt">,
<ref id="dumpt" name="dumpt">
<tag/Example/None.
</descrip>
</quote>
@ -1880,7 +1904,7 @@ be used in presence of a prototype.
<ref id="_swap" name="_swap">,
<ref id="memcpy" name="memcpy">,
<ref id="memmove" name="memmove">,
<ref id="memset" name="memset">,
<ref id="memset" name="memset">
<tag/Example/None.
</descrip>
</quote>
@ -1953,7 +1977,7 @@ sent a command to TALK and a secondary address if it needs one.
</itemize>
<tag/Availability/cc65
<tag/See also/
<ref id="cbm_k_talk" name="cbm_k_talk">,
<ref id="cbm_k_talk" name="cbm_k_talk">
<tag/Example/None.
</descrip>
</quote>
@ -2355,8 +2379,8 @@ function, in order to provide input from the keyboard.
<tag/See also/
<ref id="cbm_k_getin" name="cbm_k_getin">,
<ref id="cbm_k_udtim" name="cbm_k_udtim">,
<ref id="cgetc" name="cgetc">,
<!-- <ref id="getc" name="getc"> -->
<ref id="cgetc" name="cgetc">
<!-- <ref id="getc" name="getc">, -->
<!-- <ref id="getchar" name="getchar"> -->
<tag/Example/None.
</descrip>
@ -3274,7 +3298,7 @@ used in presence of a prototype.
<tag/Availability/cc65 (not all platforms)
<tag/See also/
<ref id="get_c128_speed" name="get_c128_speed">,
<ref id="set_c128_speed" name="set_c128_speed">,
<ref id="set_c128_speed" name="set_c128_speed">
<tag/Example/None.
</descrip>
</quote>
@ -3314,7 +3338,7 @@ used in presence of a prototype.
<tag/Availability/cc65 (not all platforms)
<tag/See also/
<ref id="get_c65_speed" name="get_c65_speed">,
<ref id="set_c65_speed" name="set_c65_speed">,
<ref id="set_c65_speed" name="set_c65_speed">
<tag/Example/None.
</descrip>
</quote>
@ -3440,11 +3464,11 @@ int main(void)
<quote>
<descrip>
<tag/Function/Dump memory to tape.
<tag/Header/<tt/<ref id="sym1.h" name="sym1.h">/
<tag/Header/<tt/<ref id="sym1.h" name="sym1.h">/, <tt/<ref id="kim1.h" name="kim1.h">/
<tag/Declaration/<tt/int __fastcall__ dumpt (unsigned char id, const void* start, const void* end);/
<tag/Description/<tt/dumpt/ saves memory onto data tape.
<tag/Notes/<itemize>
<item>The function is specific to the Sym-1.
<item>The function is specific to the Sym-1 and KIM-1.
<item>The return value is status. Non-zero status indicates an error.
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
@ -3453,7 +3477,7 @@ be used in presence of a prototype.
<tag/See also/
<ref id="beep" name="beep">,
<ref id="fdisp" name="fdisp">,
<ref id="loadt" name="loadt">,
<ref id="loadt" name="loadt">
<tag/Example/None.
</descrip>
</quote>
@ -3833,7 +3857,7 @@ switching the CPU into double clock mode.
<tag/See also/
<ref id="beep" name="beep">,
<ref id="loadt" name="loadt">,
<ref id="dumpt" name="dumpt">,
<ref id="dumpt" name="dumpt">
<tag/Example/None.
</descrip>
</quote>
@ -3949,7 +3973,8 @@ be used in presence of a prototype.
<descrip>
<tag/Function/The function returns the operating system, the program runs on.
<tag/Header/<tt/<ref id="apple2.h" name="apple2.h">,
<ref id="atari.h" name="atari.h">, <ref id="c64.h" name="c64.h">/
<ref id="atari.h" name="atari.h">, <ref id="c64.h" name="c64.h">,
<ref id="cx16.h" name="cx16.h">/
<tag/Declaration/<tt/unsigned char get_ostype (void);/
<tag/Description/<tt/get_ostype/ is machine dependent and does not exist for
all supported targets. If it exists, it returns a number that identifies the
@ -4388,6 +4413,45 @@ to undefined behaviour.
</descrip>
</quote>
<sect1>htonl<label id="htonl"><p>
<quote>
<descrip>
<tag/Function/Swaps byte order in a 32 bit word.
<tag/Header/<tt/<ref id="inet.h" name="arpa/inet.h">/
<tag/Declaration/<tt/int htonl(val)/
<tag/Description/Converts a 32 bit word from from network byte order
(big endian) to little endian (or vice-versa).
<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/See also/
<ref id="ntohl" name="ntohl">
<tag/Availability/cc65
</descrip>
</quote>
<sect1>htons<label id="htons"><p>
<quote>
<descrip>
<tag/Function/Swaps byte order in a 16 bit word.
<tag/Header/<tt/<ref id="inet.h" name="arpa/inet.h">/
<tag/Declaration/<tt/int htons(val)/
<tag/Description/Converts a 16 bit word from from network byte order
(big endian) to little endian (or vice-versa) by swapping both its bytes.
<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/See also/
<ref id="ntohs" name="ntohs">
<tag/Availability/cc65
</descrip>
</quote>
<sect1>isalnum<label id="isalnum"><p>
@ -5084,11 +5148,11 @@ used in presence of a prototype.
<quote>
<descrip>
<tag/Function/Load memory from tape.
<tag/Header/<tt/<ref id="sym1.h" name="sym1.h">/
<tag/Header/<tt/<ref id="sym1.h" name="sym1.h">/, <tt/<ref id="kim1.h" name="kim1.h">/
<tag/Declaration/<tt/int __fastcall__ loadt (unsigned char id);/
<tag/Description/<tt/loadt/ loads memory from data tape.
<tag/Notes/<itemize>
<item>The function is specific to the Sym-1.
<item>The function is specific to the Sym-1 and KIM-1.
<item>The return value is status. Non-zero status indicates an error.
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
@ -5097,7 +5161,7 @@ be used in presence of a prototype.
<tag/See also/
<ref id="beep" name="beep">,
<ref id="fdisp" name="fdisp">,
<ref id="dumpt" name="dumpt">,
<ref id="dumpt" name="dumpt">
<tag/Example/None.
</descrip>
</quote>
@ -5757,6 +5821,44 @@ memory allocated for the driver.
</descrip>
</quote>
<sect1>ntohl<label id="ntohl"><p>
<quote>
<descrip>
<tag/Function/Swaps byte order in a 32 bit word.
<tag/Header/<tt/<ref id="inet.h" name="arpa/inet.h">/
<tag/Declaration/<tt/int __fastcall__ ntohl (int val);/
<tag/Description/Converts a 32 bit word from from host byte order (little endian)
to big endian (or vice-versa).
<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/See also/
<ref id="htonl" name="htonl">
<tag/Availability/cc65
</descrip>
</quote>
<sect1>ntohs<label id="ntohs"><p>
<quote>
<descrip>
<tag/Function/Swaps byte order in a 16 bit word.
<tag/Header/<tt/<ref id="inet.h" name="arpa/inet.h">/
<tag/Declaration/<tt/int __fastcall__ ntohs (int val);/
<tag/Description/Converts a 16 bit word from from host byte order (little endian)
to big endian (or vice-versa) by swapping both its bytes.
<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/See also/
<ref id="htons" name="htons">
<tag/Availability/cc65
</descrip>
</quote>
<sect1>offsetof<label id="offsetof"><p>
<quote>
@ -6606,7 +6708,8 @@ be used in presence of a prototype.
<tag/Function/Uninstall the currently loaded driver but do not unload it.
<tag/Header/<tt/<ref id="serial.h" name="serial.h">/
<tag/Declaration/<tt/unsigned char ser_uninstall (void);/
<tag/Description/Uninstall the currently loaded driver but do not unload it.
<tag/Description/Uninstall the currently loaded driver but do not unload it. This
function returns SER_ERR_NO_DRIVER if no driver was installed, 0 otherwise.
<tag/Availability/cc65
<tag/See also/Other serial functions.
<tag/Example/None.

View File

@ -270,7 +270,7 @@ required for the correct process of GEOS sequential application building.
<p>Large GEOS applications typically don't fit in one piece in their designated
memory area. They are therefore split into overlays which are loaded into memory
on demand. The individual overlays are stored as records of a VLIR (Variable
Length Index Record) file. When GEOS starts a VLIR overlay appliation it loads
Length Index Record) file. When GEOS starts a VLIR overlay application it loads
record number 0 which is supposed to contain the main program. The record numbers
starting with 1 are to be used for the actual overlays.

View File

@ -172,6 +172,7 @@ extern void a2_auxmem_emd[];
extern void a2_stdjoy_joy[]; /* Referred to by joy_static_stddrv[] */
extern void a2_stdmou_mou[]; /* Referred to by mouse_static_stddrv[] */
extern void a2_ssc_ser[]; /* Referred to by ser_static_stddrv[] */
extern void a2_gs_ser[]; /* IIgs serial driver */
extern void a2_hi_tgi[]; /* Referred to by tgi_static_stddrv[] */
extern void a2_lo_tgi[];
#endif

View File

@ -100,6 +100,7 @@ extern void a2e_auxmem_emd[];
extern void a2e_stdjoy_joy[]; /* Referred to by joy_static_stddrv[] */
extern void a2e_stdmou_mou[]; /* Referred to by mouse_static_stddrv[] */
extern void a2e_ssc_ser[]; /* Referred to by ser_static_stddrv[] */
extern void a2e_gs_ser[]; /* IIgs serial driver */
extern void a2e_hi_tgi[]; /* Referred to by tgi_static_stddrv[] */
extern void a2e_lo_tgi[];

67
include/arpa/inet.h Normal file
View File

@ -0,0 +1,67 @@
/*****************************************************************************/
/* */
/* arpa/inet.h */
/* */
/* Endianness utilities for cc65 */
/* */
/* */
/* */
/* (C) 2023 Colin Leroy-Mira, <colin@colino.net> */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#ifndef _ARPA_INET_H
#define _ARPA_INET_H
/*****************************************************************************/
/* Code */
/*****************************************************************************/
#if (__OPT_i__ < 200)
int __fastcall__ ntohs (int val);
int __fastcall__ htons (int val);
#else
#define ntohs(x) \
( \
__AX__=(x), \
asm("sta tmp1"), \
asm("txa"), \
asm("ldx tmp1"), \
__AX__ \
)
#define htons(x) ntohs(x)
#endif
long __fastcall__ ntohl (long val);
long __fastcall__ htonl (long val);
/* End of arpa/inet.h */
#endif

View File

@ -256,6 +256,42 @@ struct __vera {
unsigned char vstart; /* Vertical start position */
unsigned char vstop; /* Vertical stop position */
};
struct { /* Visible when DCSEL flag = 2 */
unsigned char fxctrl;
unsigned char fxtilebase;
unsigned char fxmapbase;
unsigned char fxmult;
};
struct { /* Visible when DCSEL flag = 3 */
unsigned char fxxincrl;
unsigned char fxxincrh;
unsigned char fxyincrl;
unsigned char fxyincrh;
};
struct { /* Visible when DCSEL flag = 4 */
unsigned char fxxposl;
unsigned char fxxposh;
unsigned char fxyposl;
unsigned char fxyposh;
};
struct { /* Visible when DCSEL flag = 5 */
unsigned char fxxposs;
unsigned char fxyposs;
unsigned char fxpolyfilll;
unsigned char fxpolyfillh;
};
struct { /* Visible when DCSEL flag = 6 */
unsigned char fxcachel;
unsigned char fxcachem;
unsigned char fxcacheh;
unsigned char fxcacheu;
};
struct { /* Visible when DCSEL flag = 63 */
unsigned char dcver0;
unsigned char dcver1;
unsigned char dcver2;
unsigned char dcver3;
};
} display;
struct {
unsigned char config; /* Layer map geometry */

View File

@ -131,8 +131,8 @@ $(TARGETS): | ../lib
else # TARGET
CA65FLAGS =
CC65FLAGS = -Or -W error
CA65FLAGS = -g
CC65FLAGS = -g -Or -W error
EXTZP = cbm510 \
cbm610 \

View File

@ -14,6 +14,8 @@
.include "apple2.inc"
.macpack cpu
.segment "ONCE"
.ifdef __APPLE2ENH__
@ -51,8 +53,13 @@ cputdirect:
cmp WNDWDTH
bcc :+
jsr newline
left: lda #$00 ; Goto left edge of screen
left:
.if (.cpu .bitand CPU_ISET_65SC02)
stz CH ; Goto left edge of screen
.else
lda #$00 ; Goto left edge of screen
sta CH
.endif
: rts
newline:
@ -78,17 +85,18 @@ mask: and INVFLG ; Apply normal, inverse, flash
putchardirect:
pha
ldy CH
.ifdef __APPLE2ENH__
lda CH
bit RD80VID ; In 80 column mode?
bpl put ; No, just go ahead
tya
lsr ; Div by 2
tay
bcs put ; Odd cols go in main memory
bit HISCR ; Assume SET80COL
put: tay
.else
ldy CH
.endif
put: lda (BASL),Y ; Get current character
lda (BASL),Y ; Get current character
tax ; Return old character for _cgetc
pla
sta (BASL),Y

View File

@ -213,8 +213,6 @@ source: jsr $BF00
bcs error
; Check for cmdline handling
lda $0100 ; Valid cmdline?
beq jump ; No, jump to program right away
ldx file_type ; SYS file?
bne system ; Yes, check for startup filename

713
libsrc/apple2/ser/a2.gs.s Normal file
View File

@ -0,0 +1,713 @@
;
; Serial driver for the Apple IIgs Zilog Z8530.
;
; Colin Leroy-Mira <colin@colino.net>, 2023
;
; This software is licensed under the same license as cc65,
; the zlib license (see LICENSE file).
;
; Documentation from http://www.applelogic.org/files/Z8530UM.pdf (pages
; referred to where applicable)
; and https://gswv.apple2.org.za/a2zine/Utils/Z8530_SCCsamples_info.txt
.setcpu "65816"
.include "zeropage.inc"
.include "ser-kernel.inc"
.include "ser-error.inc"
.macpack module
; ------------------------------------------------------------------------
; Header. Includes jump table
.ifdef __APPLE2ENH__
module_header _a2e_gs_ser
.else
module_header _a2_gs_ser
.endif
; Driver signature
.byte $73, $65, $72 ; "ser"
.byte SER_API_VERSION ; Serial API version number
; Library reference
.addr $0000
; Jump table
.addr SER_INSTALL
.addr SER_UNINSTALL
.addr SER_OPEN
.addr SER_CLOSE
.addr SER_GET
.addr SER_PUT
.addr SER_STATUS
.addr SER_IOCTL
.addr SER_IRQ
;----------------------------------------------------------------------------
; Global variables
.bss
RecvHead: .res 1 ; Head of receive buffer
RecvTail: .res 1 ; Tail of receive buffer
RecvFreeCnt: .res 1 ; Number of bytes in receive buffer
SendHead: .res 1 ; Head of send buffer
SendTail: .res 1 ; Tail of send buffer
SendFreeCnt: .res 1 ; Number of bytes in send buffer
Stopped: .res 1 ; Flow-stopped flag
RtsOff: .res 1
RecvBuf: .res 256 ; Receive buffers: 256 bytes
SendBuf: .res 256 ; Send buffers: 256 bytes
.data
Opened: .byte $00 ; 1 when opened
Channel: .byte $00 ; Channel B by default
CurChanIrqFlags:.byte INTR_PENDING_RX_EXT_B
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
.byte %11000000 ; SER_BITS_8
TxBitTable: .byte %00000000 ; SER_BITS_5, in WR_TX_CTRL (WR5)
.byte %01000000 ; SER_BITS_6 (Ref page 5-9)
.byte %00100000 ; SER_BITS_7
.byte %01100000 ; SER_BITS_8
.rodata
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
StopTable: .byte %00000100 ; SER_STOP_1, in WR_TX_RX_CTRL (WR4)
.byte %00001100 ; SER_STOP_2 (Ref page 5-8)
ParityTable: .byte %00000000 ; SER_PAR_NONE, in WR_TX_RX_CTRL (WR4)
.byte %00000001 ; SER_PAR_ODD (Ref page 5-8)
.byte %00000011 ; SER_PAR_EVEN
.byte $FF ; SER_PAR_MARK
.byte $FF ; SER_PAR_SPACE
; ------------------------------------------------------------------------
; Addresses
SCCAREG := $C039
SCCBREG := $C038
SCCADATA := $C03B
SCCBDATA := $C03A
; We're supposed to get SerFlag's address using GetAddr on ROMs 1 and 3.
; (https://archive.org/details/IIgs_2523018_SCC_Access, page 9)
; But, it's the same value as on ROM0. As we don't expect a ROM 4 anytime
; soon with a different value, let's keep it simple.
SER_FLAG := $E10104
; ------------------------------------------------------------------------
; Write registers, read registers, and values that interest us
WR_INIT_CTRL = 0
RR_INIT_STATUS = 0
INIT_CTRL_CLEAR_EIRQ = %00010000
INIT_CTRL_CLEAR_ERR = %00110000
INIT_STATUS_READY = %00000100
INIT_STATUS_RTS = %00100000
WR_TX_RX_MODE_CTRL = 1
TX_RX_MODE_OFF = %00000000
TX_RX_MODE_RXIRQ = %00010001
WR_RX_CTRL = 3 ; (Ref page 5-7)
RR_RX_STATUS = 9 ; Corresponding status register
RX_CTRL_ON = %00000001 ; ORed, Rx enabled
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
TX_CTRL_ON = %00001000 ; ORed, Tx enabled
TX_CTRL_OFF = %11110111 ; ANDed,Tx disabled
TX_DTR_ON = %01111111 ; ANDed,DTR ON (high)
TX_DTR_OFF = %10000000 ; ORed, DTR OFF
TX_RTS_ON = %00000010 ; ORed, RTS ON (low)
TX_RTS_OFF = %11111101 ; ANDed, RTS OFF
WR_MASTER_IRQ_RST = 9 ; (Ref page 5-14)
MASTER_IRQ_SHUTDOWN = %00000010 ; STA'd
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
RR_SPEC_COND_STATUS = 1 ; (Ref page 5-23)
SPEC_COND_FRAMING_ERR = %01000000
SPEC_COND_OVERRUN_ERR = %00100000
RR_IRQ_STATUS = 2 ; (Ref page 5-24)
IRQ_MASQ = %01110000 ; ANDed
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.
; Input: X as channel
; Y as register
; Output: A
readSSCReg:
cpx #0
bne ReadAreg
sty SCCBREG
lda SCCBREG
rts
ReadAreg:
sty SCCAREG
lda SCCAREG
rts
; Write value of A to a register.
; Input: X as channel
; Y as register
writeSCCReg:
cpx #0
bne WriteAreg
sty SCCBREG
sta SCCBREG
rts
WriteAreg:
sty SCCAREG
sta SCCAREG
rts
;----------------------------------------------------------------------------
; SER_INSTALL: Is called after the driver is loaded into memory. If possible,
; check if the hardware is present. Must return an SER_ERR_xx code in a/x.
;
; Since we don't have to manage the IRQ vector on the Apple II, this is
; actually the same as:
;
; SER_UNINSTALL: Is called before the driver is removed from memory.
; No return code required (the driver is removed from memory on return).
;
; and:
;
; SER_CLOSE: Close the port and disable interrupts. Called without parameters.
; Must return an SER_ERR_xx code in a/x.
SER_INSTALL:
SER_UNINSTALL:
SER_CLOSE:
; Check if this is a IIgs (Apple II Miscellaneous TechNote #7,
; Apple II Family Identification)
sec
bit $C082
jsr $FE1F
bit $C080
bcc IIgs
lda #SER_ERR_NO_DEVICE ; Not a IIgs
ldx #$00 ; Promote char return value
rts
IIgs:
ldx Opened ; Check for open port
beq :+
ldx Channel
; Deactivate interrupts
sei
ldy #WR_MASTER_IRQ_RST
lda #MASTER_IRQ_SHUTDOWN
jsr writeSCCReg
ldy #WR_TX_RX_MODE_CTRL
lda #TX_RX_MODE_OFF
jsr writeSCCReg
; Reset SerFlag to what it was
lda SerFlagOrig
sta SER_FLAG
lda SCCBDATA
; Clear external interrupts (twice)
ldy #WR_INIT_CTRL
lda #INIT_CTRL_CLEAR_EIRQ
jsr writeSCCReg
jsr writeSCCReg
; Reset MIE for firmware use
ldy #WR_MASTER_IRQ_RST
lda #MASTER_IRQ_MIE_RST
jsr writeSCCReg
ldx #$00
stx Opened ; Mark port as closed
cli
: txa ; Promote char return value
rts
;----------------------------------------------------------------------------
; SER_OPEN: A pointer to a ser_params structure is passed in ptr1.
; Must return an SER_ERR_xx code in a/x.
SER_OPEN:
sei
; Check if the handshake setting is valid
ldy #SER_PARAMS::HANDSHAKE ; Handshake
lda (ptr1),y
cmp #SER_HS_HW ; This is all we support
bne InvParam
; Initialize buffers
ldy #$00
sty Stopped
sty RecvHead
sty RecvTail
sty SendHead
sty SendTail
dey ; Y = 255
sty RecvFreeCnt
sty SendFreeCnt
ldx Channel
ldy #RR_INIT_STATUS ; Hit rr0 once to sync up
jsr readSSCReg
ldy #WR_MISC_CTRL ; Turn everything off
lda #$00
jsr writeSCCReg
ldy #SER_PARAMS::STOPBITS
lda (ptr1),y ; Stop bits
tay
lda StopTable,y ; Get value
pha
ldy #SER_PARAMS::PARITY
lda (ptr1),y ; Parity bits
tay
pla
ora ParityTable,y ; Get value
bmi InvParam
ora #TX_RX_CLOCK_MUL
ldy #WR_TX_RX_CTRL ; Setup stop & parity bits
jsr writeSCCReg
cpx #$00
bne ClockA
ClockB:
ldy #WR_CLOCK_CTRL
lda #CLOCK_CTRL_CH_B
jsr writeSCCReg
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
sta CurChanIrqFlags
SetBaud:
ldy #SER_PARAMS::BAUDRATE
lda (ptr1),y ; Baudrate index - cc65 value
tay
lda BaudTable,y ; Get chip value from Low/High tables
bpl BaudOK ; Verify baudrate is supported
InvParam:
lda #SER_ERR_INIT_FAILED
ldy #$00 ; Mark port closed
bra SetupOut
BaudOK:
tay
lda BaudLowTable,y ; Get low byte
phy
ldy #WR_BAUDL_CTRL
jsr writeSCCReg
ply
lda BaudHighTable,y ; Get high byte
ldy #WR_BAUDH_CTRL
jsr writeSCCReg
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
tay
lda RxBitTable,y ; Data bits for RX
ora #RX_CTRL_ON ; and turn RX on
phy
ldy #WR_RX_CTRL
jsr writeSCCReg
ply
lda TxBitTable,y ; Data bits for TX
ora #TX_CTRL_ON ; and turn TX on
and #TX_DTR_ON
sta RtsOff ; Save value for flow control
ora #TX_RTS_ON
ldy #WR_TX_CTRL
jsr writeSCCReg
ldy #WR_IRQ_CTRL
lda #IRQ_CLEANUP_EIRQ
jsr writeSCCReg
ldy #WR_INIT_CTRL ; Clear ext status (write twice)
lda #INIT_CTRL_CLEAR_EIRQ
jsr writeSCCReg
jsr writeSCCReg
ldy #WR_TX_RX_MODE_CTRL ; Activate RX IRQ
lda #TX_RX_MODE_RXIRQ
jsr writeSCCReg
lda SCCBREG ; Activate master IRQ
ldy #WR_MASTER_IRQ_RST
lda #MASTER_IRQ_SET
jsr writeSCCReg
lda SER_FLAG ; Get SerFlag's current value
sta SerFlagOrig ; and save it
cpx #$00
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:
sta SER_FLAG
ldy #$01 ; Mark port opened
lda #SER_ERR_OK
SetupOut:
ldx #$00 ; Promote char return value
sty Opened
cli
rts
;----------------------------------------------------------------------------
; SER_GET: Will fetch a character from the receive buffer and store it into the
; variable pointed to by ptr1. If no data is available, SER_ERR_NO_DATA is
; returned.
SER_GET:
ldx Channel
lda RecvFreeCnt ; Check for buffer empty
cmp #$FF
beq NoData
ldy Stopped ; Check for flow stopped
beq :+
cmp #63 ; Enough free?
bcc :+
stz Stopped ; Release flow control
lda RtsOff
ora #TX_RTS_ON
ldy #WR_TX_CTRL
jsr writeSCCReg
: ldy RecvHead ; Get byte from buffer
lda RecvBuf,y
inc RecvHead
inc RecvFreeCnt
sta (ptr1)
lda #SER_ERR_OK
.assert SER_ERR_OK = 0, error
tax
rts
NoData:
lda #SER_ERR_NO_DATA
ldx #$00 ; Promote char return value
rts
;----------------------------------------------------------------------------
; SER_PUT: Output character in A.
; Must return an SER_ERR_xx code in a/x.
SER_PUT:
ldx Channel
ldy SendFreeCnt ; Anything to send first?
iny ; Y = $FF?
beq :+
pha
lda #$00 ; TryHard = false
jsr TryToSend
pla
: ldy SendFreeCnt ; Do we have room to store byte?
bne :+
lda #SER_ERR_OVERFLOW
ldx #$00
rts
: ldy SendTail ; Put byte into send buffer & send
sta SendBuf,y
inc SendTail
dec SendFreeCnt
lda #$FF ; TryHard = true
jsr TryToSend
lda #SER_ERR_OK
.assert SER_ERR_OK = 0, error
tax
rts
;----------------------------------------------------------------------------
; SER_STATUS: Return the status in the variable pointed to by ptr1.
; Must return an SER_ERR_xx code in a/x.
; We provide the read register 0, containing interesting info like
; INIT_STATUS_READY (hardware handshake status) or INIT_STATUS_RTS
; (ready to send).
SER_STATUS:
ldx Channel
lda SCCBREG,x
ldx #$00
sta (ptr1)
.assert SER_ERR_OK = 0, error
txa
rts
;----------------------------------------------------------------------------
; SER_IOCTL: Driver defined entry point. The wrapper will pass a pointer to ioctl
; specific data in ptr1, and the ioctl code in A.
; Sets communication channel A or B (A = 1, B = 0)
; Must return an SER_ERR_xx code in a/x.
SER_IOCTL:
ora ptr1+1 ; Check data msb and code to be 0
bne :+
ldx ptr1 ; Check data lsb to be 0 or 1
bmi :+
cpx #$02
bcs :+
stx Channel
.assert SER_ERR_OK = 0, error
tax
rts
: lda #SER_ERR_INV_IOCTL
ldx #$00 ; Promote char return value
rts
;----------------------------------------------------------------------------
; SER_IRQ: Called from the builtin runtime IRQ handler as a subroutine. All
; registers are already saved, no parameters are passed, but the carry flag
; is clear on entry. The routine must return with carry set if the interrupt
; was handled, otherwise with carry clear.
SER_IRQ:
ldy #RR_INTR_PENDING_STATUS ; IRQ status is always in A reg
sty SCCAREG
lda SCCAREG
and CurChanIrqFlags ; Is this ours?
beq Done
and #INTR_IS_RX ; Is this an RX irq?
beq CheckSpecial
ldx Channel
lda SCCBDATA,x ; Get byte
ldx RecvFreeCnt ; Check if we have free space left
beq Flow ; Jump if no space in receive buffer
ldy RecvTail ; Load buffer pointer
sta RecvBuf,y ; Store received byte in buffer
inc RecvTail ; Increment buffer pointer
dec RecvFreeCnt ; Decrement free space counter
cpx #33
bcc Flow ; Assert flow control if buffer space low
rts ; Interrupt handled (carry already set)
CheckSpecial:
; Always check IRQ special flags from Channel B (Ref page 5-24)
ldy #RR_IRQ_STATUS
sty SCCBREG
lda SCCBREG
and #IRQ_MASQ
cmp #IRQ_SPECIAL
beq Special
; Clear exint
ldx Channel
ldy #WR_INIT_CTRL
lda #INIT_CTRL_CLEAR_EIRQ
jsr writeSCCReg
sec
rts
Flow: ldx Channel ; Assert flow control if buffer space too low
ldy #WR_TX_CTRL
lda RtsOff
jsr writeSCCReg
sta Stopped
sec ; Interrupt handled
Done: rts
Special:ldx Channel
ldy #RR_SPEC_COND_STATUS
jsr readSSCReg
tax
and #SPEC_COND_FRAMING_ERR
bne BadChar
txa
and #SPEC_COND_OVERRUN_ERR
beq BadChar
ldy #WR_INIT_CTRL
lda #INIT_CTRL_CLEAR_ERR
jsr writeSCCReg
sec
rts
BadChar:
lda SCCBDATA,x ; Remove char in error
sec
rts
;----------------------------------------------------------------------------
; Try to send a byte. Internal routine. A = TryHard, X = Channel
TryToSend:
sta tmp1 ; Remember tryHard flag
Again: lda SendFreeCnt ; Anything to send?
cmp #$FF
beq Quit ; No
lda Stopped ; Check for flow stopped
bne Quit ; Bail out if it is
Wait:
lda SCCBREG,x ; Check that we're ready to send
tay
and #INIT_STATUS_READY
beq NotReady
tya
and #INIT_STATUS_RTS ; Ready to send
bne Send
NotReady:
bit tmp1 ; Keep trying if must try hard
bmi Wait
Quit: rts
Send: ldy SendHead ; Send byte
lda SendBuf,y
sta SCCBDATA,x
inc SendHead
inc SendFreeCnt
jmp Again ; Continue flushing TX buffer

View File

@ -26,6 +26,7 @@
.include "ser-error.inc"
.macpack module
.macpack cpu
; ------------------------------------------------------------------------
; Header. Includes jump table
@ -37,8 +38,8 @@
.endif
; Driver signature
.byte $73, $65, $72 ; "ser"
.byte SER_API_VERSION ; Serial API version number
.byte $73, $65, $72 ; "ser"
.byte SER_API_VERSION ; Serial API version number
; Library reference
.addr $0000
@ -57,13 +58,17 @@
;----------------------------------------------------------------------------
; I/O definitions
.if (.cpu .bitand CPU_ISET_65C02)
ACIA := $C088
.else
Offset = $8F ; Move 6502 false read out of I/O to page $BF
ACIA := $C088-Offset
.endif
ACIA = $C088-Offset
ACIA_DATA = ACIA+0 ; Data register
ACIA_STATUS = ACIA+1 ; Status register
ACIA_CMD = ACIA+2 ; Command register
ACIA_CTRL = ACIA+3 ; Control register
ACIA_DATA := ACIA+0 ; Data register
ACIA_STATUS := ACIA+1 ; Status register
ACIA_CMD := ACIA+2 ; Command register
ACIA_CTRL := ACIA+3 ; Control register
;----------------------------------------------------------------------------
; Global variables
@ -72,16 +77,17 @@ ACIA_CTRL = ACIA+3 ; Control register
RecvHead: .res 1 ; Head of receive buffer
RecvTail: .res 1 ; Tail of receive buffer
RecvFreeCnt: .res 1 ; Number of bytes in receive buffer
RecvFreeCnt: .res 1 ; Number of free bytes in receive buffer
SendHead: .res 1 ; Head of send buffer
SendTail: .res 1 ; Tail of send buffer
SendFreeCnt: .res 1 ; Number of bytes in send buffer
SendFreeCnt: .res 1 ; Number of free bytes in send buffer
Stopped: .res 1 ; Flow-stopped flag
RtsOff: .res 1 ;
RtsOff: .res 1 ; Cached value of command register with
; flow stopped
RecvBuf: .res 256 ; Receive buffers: 256 bytes
SendBuf: .res 256 ; Send buffers: 256 bytes
RecvBuf: .res 256 ; Receive buffer: 256 bytes
SendBuf: .res 256 ; Send buffer: 256 bytes
Index: .res 1 ; I/O register index
@ -91,8 +97,9 @@ Slot: .byte $02 ; Default to SSC in slot 2
.rodata
; Tables used to translate RS232 params into register values
BaudTable: ; bit7 = 1 means setting is invalid
BaudTable: ; Table used to translate RS232 baudrate param
; into control register value
; bit7 = 1 means setting is invalid
.byte $FF ; SER_BAUD_45_5
.byte $01 ; SER_BAUD_50
.byte $02 ; SER_BAUD_75
@ -113,30 +120,61 @@ BaudTable: ; bit7 = 1 means setting is invalid
.byte $FF ; SER_BAUD_57600
.byte $FF ; SER_BAUD_115200
.byte $FF ; SER_BAUD_230400
BitTable:
BitTable: ; Table used to translate RS232 databits param
; into control register value
.byte $60 ; SER_BITS_5
.byte $40 ; SER_BITS_6
.byte $20 ; SER_BITS_7
.byte $00 ; SER_BITS_8
StopTable:
StopTable: ; Table used to translate RS232 stopbits param
; into control register value
.byte $00 ; SER_STOP_1
.byte $80 ; SER_STOP_2
ParityTable:
ParityTable: ; Table used to translate RS232 parity param
; into command register value
.byte $00 ; SER_PAR_NONE
.byte $20 ; SER_PAR_ODD
.byte $60 ; SER_PAR_EVEN
.byte $A0 ; SER_PAR_MARK
.byte $E0 ; SER_PAR_SPACE
IdOfsTable:
IdOfsTable: ; Table of bytes positions, used to check five
; specific bytes on the slot's firmware to make
; sure this is an SSC (or Apple //c comm port)
; firmware that drives an ACIA 6551 chip.
;
; The SSC firmware and the Apple //c(+) comm
; port firmware all begin with a BIT instruction.
; The IIgs, on the other hand, has a
; Zilog Z8530 chip and its firmware starts with
; a SEP instruction. We don't want to load this
; driver on the IIgs' serial port. We'll
; differentiate the firmware on this byte.
;
; The next four bytes we check are the Pascal
; Firmware Protocol Bytes that identify a
; serial card. Those are the same bytes for
; SSC firmwares, Apple //c firmwares and IIgs
; Zilog Z8530 firmwares - which is the reason
; we have to check for the firmware's first
; instruction too.
.byte $00 ; First instruction
.byte $05 ; Pascal 1.0 ID byte
.byte $07 ; Pascal 1.0 ID byte
.byte $0B ; Pascal 1.1 generic signature byte
.byte $0C ; Device signature byte
IdValTable:
.byte $38 ; Fixed
.byte $18 ; Fixed
.byte $01 ; Fixed
.byte $31 ; Serial or parallel I/O card type 1
IdValTable: ; Table of expected values for the five checked
; bytes
.byte $2C ; BIT
.byte $38 ; ID Byte 0 (from Pascal 1.0), fixed
.byte $18 ; ID Byte 1 (from Pascal 1.0), fixed
.byte $01 ; Generic signature for Pascal 1.1, fixed
.byte $31 ; Device signature byte (serial or
; parallel I/O card type 1)
IdTableLen = * - IdValTable
@ -163,12 +201,10 @@ SER_CLOSE:
ldx Index ; Check for open port
beq :+
; Deactivate DTR and disable 6551 interrupts
lda #%00001010
lda #%00001010 ; Deactivate DTR and disable 6551 interrupts
sta ACIA_CMD,x
; Done, return an error code
: lda #SER_ERR_OK
: lda #SER_ERR_OK ; Done, return an error code
.assert SER_ERR_OK = 0, error
tax
stx Index ; Mark port as closed
@ -185,96 +221,96 @@ SER_OPEN:
ora Slot
sta ptr2+1
; Check Pascal 1.1 Firmware Protocol ID bytes
: ldy IdOfsTable,x
: ldy IdOfsTable,x ; Check Pascal 1.1 Firmware Protocol ID bytes
lda IdValTable,x
cmp (ptr2),y
bne NoDevice
bne NoDev
inx
cpx #IdTableLen
bcc :-
; Convert slot to I/O register index
lda Slot
lda Slot ; Convert slot to I/O register index
asl
asl
asl
asl
adc #Offset ; Assume carry to be clear
.if .not (.cpu .bitand CPU_ISET_65C02)
adc #Offset ; Assume carry to be clear
.endif
tax
; Check if the handshake setting is valid
ldy #SER_PARAMS::HANDSHAKE ; Handshake
ldy #SER_PARAMS::HANDSHAKE
lda (ptr1),y
cmp #SER_HS_HW ; This is all we support
bne InvParam
cmp #SER_HS_HW ; This is all we support
bne InvParm
; Initialize buffers
ldy #$00
ldy #$00 ; Initialize buffers
sty Stopped
sty RecvHead
sty RecvTail
sty SendHead
sty SendTail
dey ; Y = 255
dey ; Y = 255
sty RecvFreeCnt
sty SendFreeCnt
; Set the value for the control register, which contains stop bits,
; word length and the baud rate.
ldy #SER_PARAMS::BAUDRATE
lda (ptr1),y ; Baudrate index
lda (ptr1),y ; Baudrate index
tay
lda BaudTable,y ; Get 6551 value
bmi InvBaud ; Branch if rate not supported
lda BaudTable,y ; Get 6551 value
bmi InvBaud ; Branch if rate not supported
sta tmp1
ldy #SER_PARAMS::DATABITS ; Databits
lda (ptr1),y
ldy #SER_PARAMS::DATABITS
lda (ptr1),y ; Databits index
tay
lda BitTable,y
lda BitTable,y ; Get 6551 value
ora tmp1
sta tmp1
ldy #SER_PARAMS::STOPBITS ; Stopbits
lda (ptr1),y
ldy #SER_PARAMS::STOPBITS
lda (ptr1),y ; Stopbits index
tay
lda StopTable,y
lda StopTable,y ; Get 6551 value
ora tmp1
ora #%00010000 ; Receiver clock source = baudrate
ora #%00010000 ; Set receiver clock source = baudrate
sta ACIA_CTRL,x
; Set the value for the command register. We remember the base value
; in RtsOff, since we will have to manipulate ACIA_CMD often.
ldy #SER_PARAMS::PARITY ; Parity
lda (ptr1),y
ldy #SER_PARAMS::PARITY
lda (ptr1),y ; Parity index
tay
lda ParityTable,y
ora #%00000001 ; DTR active
sta RtsOff
ora #%00001000 ; Enable receive interrupts
lda ParityTable,y ; Get 6551 value
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
; Done
stx Index ; Mark port as open
stx Index ; Mark port as open
lda #SER_ERR_OK
.assert SER_ERR_OK = 0, error
tax
rts
; Device (hardware) not found
NoDevice:lda #SER_ERR_NO_DEVICE
ldx #0 ; return value is char
NoDev: lda #SER_ERR_NO_DEVICE
ldx #$00 ; Promote char return value
rts
; Invalid parameter
InvParam:lda #SER_ERR_INIT_FAILED
ldx #0 ; return value is char
InvParm:lda #SER_ERR_INIT_FAILED
ldx #$00 ; Promote char return value
rts
; Baud rate not available
InvBaud:lda #SER_ERR_BAUD_UNAVAIL
ldx #0 ; return value is char
ldx #$00 ; Promote char return value
rts
;----------------------------------------------------------------------------
@ -284,38 +320,38 @@ InvBaud:lda #SER_ERR_BAUD_UNAVAIL
SER_GET:
ldx Index
ldy SendFreeCnt ; Send data if necessary
iny ; Y == $FF?
beq :+
lda #$00 ; TryHard = false
jsr TryToSend
; Check for buffer empty
: lda RecvFreeCnt ; (25)
lda RecvFreeCnt ; Check for buffer empty
cmp #$FF
bne :+
lda #SER_ERR_NO_DATA
ldx #0 ; return value is char
ldx #$00 ; Promote char return value
rts
; Check for flow stopped & enough free: release flow control
: ldy Stopped ; (34)
: ldy Stopped ; Check for flow stopped
beq :+
cmp #63
cmp #63 ; Enough free?
bcc :+
.if (.cpu .bitand CPU_ISET_65C02)
stz Stopped ; Release flow control
.else
lda #$00
sta Stopped
.endif
lda RtsOff
ora #%00001000
sta ACIA_CMD,x
; Get byte from buffer
: ldy RecvHead ; (41)
: ldy RecvHead ; Get byte from buffer
lda RecvBuf,y
inc RecvHead
inc RecvFreeCnt
ldx #$00 ; (59)
ldx #$00
.if (.cpu .bitand CPU_ISET_65C02)
sta (ptr1) ; Store it for caller
.else
sta (ptr1,x)
.endif
txa ; Return code = 0
rts
@ -326,28 +362,26 @@ SER_GET:
SER_PUT:
ldx Index
; Try to send
ldy SendFreeCnt
iny ; Y = $FF?
ldy SendFreeCnt ; Anything to send first?
cpy #$FF ; No
beq :+
pha
lda #$00 ; TryHard = false
jsr TryToSend
jsr TryToSend ; Try to flush send buffer
pla
; Put byte into send buffer & send
: ldy SendFreeCnt
ldy SendFreeCnt ; Reload SendFreeCnt after TryToSend
bne :+
lda #SER_ERR_OVERFLOW
ldx #0 ; return value is char
ldx #$00 ; Promote char return value
rts
: ldy SendTail
: ldy SendTail ; Put byte into send buffer
sta SendBuf,y
inc SendTail
dec SendFreeCnt
lda #$FF ; TryHard = true
jsr TryToSend
jsr TryToSend ; Flush send buffer
lda #SER_ERR_OK
.assert SER_ERR_OK = 0, error
tax
@ -369,26 +403,25 @@ SER_STATUS:
;----------------------------------------------------------------------------
; SER_IOCTL: Driver defined entry point. The wrapper will pass a pointer to ioctl
; specific data in ptr1, and the ioctl code in A.
; The ioctl data is the slot number to open.
; Must return an SER_ERR_xx code in a/x.
SER_IOCTL:
; Check data msb and code to be 0
ora ptr1+1
ora ptr1+1 ; Check data msb and code to be 0
bne :+
; Check data lsb to be [1..7]
ldx ptr1
ldx ptr1 ; Check data lsb to be [1..7]
beq :+
cpx #7+1
bcs :+
stx Slot
stx Slot ; Store slot
.assert SER_ERR_OK = 0, error
tax
rts
: lda #SER_ERR_INV_IOCTL
ldx #0 ; return value is char
ldx #$00 ; Promote char return value
rts
;----------------------------------------------------------------------------
@ -404,19 +437,18 @@ SER_IRQ:
and #$08
beq Done ; Jump if no ACIA interrupt
lda ACIA_DATA,x ; Get byte from ACIA
ldy RecvFreeCnt ; Check if we have free space left
ldx RecvFreeCnt ; Check if we have free space left
beq Flow ; Jump if no space in receive buffer
ldy RecvTail ; Load buffer pointer
sta RecvBuf,y ; Store received byte in buffer
inc RecvTail ; Increment buffer pointer
dec RecvFreeCnt ; Decrement free space counter
ldy RecvFreeCnt ; Check for buffer space low
cpy #33
cpx #33 ; Check for buffer space low
bcc Flow ; Assert flow control if buffer space low
rts ; Interrupt handled (carry already set)
; Assert flow control if buffer space too low
Flow: lda RtsOff
Flow: ldx Index ; Assert flow control if buffer space too low
lda RtsOff
sta ACIA_CMD,x
sta Stopped
sec ; Interrupt handled
@ -427,26 +459,24 @@ Done: rts
TryToSend:
sta tmp1 ; Remember tryHard flag
Again: lda SendFreeCnt
cmp #$FF
beq Quit ; Bail out
NextByte:
lda SendFreeCnt ; Is there anything to send? This can happen if
cmp #$FF ; we got interrupted by RX while sending, and
beq Quit ; flow control was asserted.
; Check for flow stopped
lda Stopped
bne Quit ; Bail out
Again: lda Stopped ; Is flow stopped?
bne Quit ; Yes, Bail out
; Check that ACIA is ready to send
lda ACIA_STATUS,x
lda ACIA_STATUS,x ; Check that ACIA is ready to send
and #$10
bne Send
bne Send ; It is!
bit tmp1 ; Keep trying if must try hard
bmi Again
Quit: rts
; Send byte and try again
Send: ldy SendHead
Send: ldy SendHead ; Get first byte to send
lda SendBuf,y
sta ACIA_DATA,x
sta ACIA_DATA,x ; Send it
inc SendHead
inc SendFreeCnt
jmp Again
jmp NextByte ; And try next one

View File

@ -227,14 +227,8 @@ InvBaud:lda #<SER_ERR_BAUD_UNAVAIL
; returned.
SER_GET:
ldy SendFreeCnt ; Send data if necessary
iny ; Y == $FF?
beq :+
lda #$00 ; TryHard = false
jsr TryToSend
; Check for buffer empty
: lda RecvFreeCnt ; (25)
lda RecvFreeCnt ; (25)
cmp #$FF
bne :+
lda #SER_ERR_NO_DATA
@ -269,20 +263,21 @@ SER_GET:
SER_PUT:
; Try to send
ldy SendFreeCnt
iny ; Y = $FF?
cpy #$FF ; Nothing to flush
beq :+
pha
lda #$00 ; TryHard = false
jsr TryToSend
pla
; Put byte into send buffer & send
: ldy SendFreeCnt
; Reload SendFreeCnt after TryToSend
ldy SendFreeCnt
bne :+
lda #SER_ERR_OVERFLOW
ldx #0 ; return value is char
rts
; Put byte into send buffer & send
: ldy SendTail
sta SendBuf,y
inc SendTail
@ -329,19 +324,19 @@ SER_IRQ:
and #$08
beq Done ; Jump if no ACIA interrupt
lda ACIA::DATA,x ; Get byte from ACIA
ldy RecvFreeCnt ; Check if we have free space left
ldx RecvFreeCnt ; Check if we have free space left
beq Flow ; Jump if no space in receive buffer
ldy RecvTail ; Load buffer pointer
sta RecvBuf,y ; Store received byte in buffer
inc RecvTail ; Increment buffer pointer
dec RecvFreeCnt ; Decrement free space counter
ldy RecvFreeCnt ; Check for buffer space low
cpy #33
cpx #33
bcc Flow ; Assert flow control if buffer space low
rts ; Interrupt handled (carry already set)
; Assert flow control if buffer space too low
Flow: lda RtsOff
Flow: ldx Index ; Reload port
lda RtsOff
sta ACIA::CMD,x
sta Stopped
sec ; Interrupt handled
@ -352,12 +347,13 @@ Done: rts
TryToSend:
sta tmp1 ; Remember tryHard flag
Again: lda SendFreeCnt
NextByte:
lda SendFreeCnt
cmp #$FF
beq Quit ; Bail out
; Check for flow stopped
lda Stopped
Again: lda Stopped
bne Quit ; Bail out
; Check that ACIA is ready to send
@ -374,4 +370,4 @@ Send: ldy SendHead
sta ACIA::DATA
inc SendHead
inc SendFreeCnt
jmp Again
jmp NextByte

View File

@ -314,15 +314,10 @@ SER_CLOSE:
;
SER_GET:
ldx SendFreeCnt ; Send data if necessary
inx ; X == $FF?
beq @L1
lda #$00
jsr TryToSend
; Check for buffer empty
@L1: lda RecvFreeCnt ; (25)
lda RecvFreeCnt ; (25)
cmp #$ff
bne @L2
lda #SER_ERR_NO_DATA
@ -362,21 +357,23 @@ SER_PUT:
; Try to send
ldx SendFreeCnt
inx ; X = $ff?
cpx #$FF ; Nothing to flush
beq @L2
pha
lda #$00
jsr TryToSend
pla
; Put byte into send buffer & send
; Reload SendFreeCnt after TryToSend
@L2: ldx SendFreeCnt
bne @L3
ldx SendFreeCnt
bne @L2
lda #SER_ERR_OVERFLOW ; X is already zero
rts
@L3: ldx SendTail
; Put byte into send buffer & send
@L2: ldx SendTail
sta SendBuf,x
inc SendTail
dec SendFreeCnt
@ -466,25 +463,25 @@ NmiHandler:
sta tmp1 ; Remember tryHard flag
@L0: lda SendFreeCnt
cmp #$ff
beq @L3 ; Bail out
beq @L2 ; Bail out
; Check for flow stopped
@L1: lda Stopped
bne @L3 ; Bail out
bne @L2 ; Bail out
; Check that swiftlink is ready to send
@L2: lda ACIA_STATUS
lda ACIA_STATUS
and #$10
bne @L4
bne @L3
bit tmp1 ;keep trying if must try hard
bmi @L0
@L3: rts
bmi @L1
@L2: rts
; Send byte and try again
@L4: ldx SendHead
@L3: ldx SendHead
lda SendBuf,x
sta ACIA_DATA
inc SendHead

View File

@ -288,15 +288,10 @@ SER_CLOSE:
;
SER_GET:
ldx SendFreeCnt ; Send data if necessary
inx ; X == $FF?
beq @L1
lda #$00
jsr TryToSend
; Check for buffer empty
@L1: lda RecvFreeCnt ; (25)
lda RecvFreeCnt ; (25)
cmp #$ff
bne @L2
lda #SER_ERR_NO_DATA
@ -336,21 +331,23 @@ SER_PUT:
; Try to send
ldx SendFreeCnt
inx ; X = $ff?
cpx #$FF ; Nothing to flush
beq @L2
pha
lda #$00
jsr TryToSend
pla
; Put byte into send buffer & send
; Reload SendFreeCnt after TryToSend
@L2: ldx SendFreeCnt
bne @L3
ldx SendFreeCnt
bne @L2
lda #SER_ERR_OVERFLOW ; X is already zero
rts
@L3: ldx SendTail
; Put byte into send buffer & send
@L2: ldx SendTail
sta SendBuf,x
inc SendTail
dec SendFreeCnt
@ -443,25 +440,25 @@ NmiHandler:
sta tmp1 ; Remember tryHard flag
@L0: lda SendFreeCnt
cmp #$ff
beq @L3 ; Bail out
beq @L2 ; Bail out
; Check for flow stopped
@L1: lda Stopped
bne @L3 ; Bail out
bne @L2 ; Bail out
; Check that swiftlink is ready to send
@L2: lda ACIA_STATUS
lda ACIA_STATUS
and #$10
bne @L4
bne @L3
bit tmp1 ;keep trying if must try hard
bmi @L0
@L3: rts
bmi @L1
@L2: rts
; Send byte and try again
@L4: ldx SendHead
@L3: ldx SendHead
lda SendBuf,x
sta ACIA_DATA
inc SendHead

View File

@ -244,15 +244,10 @@ InvBaud:
;
SER_GET:
ldx SendFreeCnt ; Send data if necessary
inx ; X == $FF?
beq @L1
lda #$00
jsr TryToSend
; Check for buffer empty
@L1: lda RecvFreeCnt
lda RecvFreeCnt
cmp #$ff
bne @L2
lda #SER_ERR_NO_DATA
@ -292,21 +287,23 @@ SER_PUT:
; Try to send
ldx SendFreeCnt
inx ; X = $ff?
cpx #$FF ; Nothing to flush
beq @L2
pha
lda #$00
jsr TryToSend
pla
; Put byte into send buffer & send
; Reload SendFreeCnt after TryToSend
@L2: ldx SendFreeCnt
bne @L3
ldx SendFreeCnt
bne @L2
lda #SER_ERR_OVERFLOW ; X is already zero
rts
@L3: ldx SendTail
; Put byte into send buffer & send
@L2: ldx SendTail
sta SendBuf,x
inc SendTail
dec SendFreeCnt
@ -395,31 +392,31 @@ SER_IRQ:
sta IndReg ; Switch to the system bank
@L0: lda SendFreeCnt
cmp #$ff
beq @L3 ; Bail out
beq @L2 ; Bail out
; Check for flow stopped
@L1: lda Stopped
bne @L3 ; Bail out
bne @L2 ; Bail out
; Check that swiftlink is ready to send
@L2: ldy #ACIA::STATUS
ldy #ACIA::STATUS
lda (acia),y
and #$10
bne @L4
bne @L3
bit tmp1 ; Keep trying if must try hard
bmi @L0
bmi @L1
; Switch back the bank and return
@L3: lda ExecReg
@L2: lda ExecReg
sta IndReg
rts
; Send byte and try again
@L4: ldx SendHead
@L3: ldx SendHead
lda SendBuf,x
ldy #ACIA::DATA
sta (acia),y

View File

@ -245,15 +245,10 @@ InvBaud:
;
SER_GET:
ldx SendFreeCnt ; Send data if necessary
inx ; X == $FF?
beq @L1
lda #$00
jsr TryToSend
; Check for buffer empty
@L1: lda RecvFreeCnt
lda RecvFreeCnt
cmp #$ff
bne @L2
lda #SER_ERR_NO_DATA
@ -293,21 +288,23 @@ SER_PUT:
; Try to send
ldx SendFreeCnt
inx ; X = $ff?
cpx #$ff ; Nothing to flush
beq @L2
pha
lda #$00
jsr TryToSend
pla
; Put byte into send buffer & send
; Reload SendFreeCnt after TryToSend
@L2: ldx SendFreeCnt
bne @L3
ldx SendFreeCnt
bne @L2
lda #SER_ERR_OVERFLOW ; X is already zero
rts
@L3: ldx SendTail
; Put byte into send buffer & send
@L2: ldx SendTail
sta SendBuf,x
inc SendTail
dec SendFreeCnt
@ -395,31 +392,31 @@ SER_IRQ:
sta IndReg ; Switch to the system bank
@L0: lda SendFreeCnt
cmp #$ff
beq @L3 ; Bail out
beq @L2 ; Bail out
; Check for flow stopped
@L1: lda Stopped
bne @L3 ; Bail out
bne @L2 ; Bail out
; Check that swiftlink is ready to send
@L2: ldy #ACIA::STATUS
ldy #ACIA::STATUS
lda (acia),y
and #$10
bne @L4
bne @L3
bit tmp1 ; Keep trying if must try hard
bmi @L0
bmi @L1
; Switch back the bank and return
@L3: lda ExecReg
@L2: lda ExecReg
sta IndReg
rts
; Send byte and try again
@L4: ldx SendHead
@L3: ldx SendHead
lda SendBuf,x
ldy #ACIA::DATA
sta (acia),y

32
libsrc/common/ntohl.s Normal file
View File

@ -0,0 +1,32 @@
;
; Colin Leroy-Mira <colin@colino.net>, 2023-09-06
;
; int __fastcall__ ntohl (long val);
;
.export _ntohl, _htonl
.import popa
.importzp tmp1, tmp2, sreg
_htonl := _ntohl
_ntohl:
; The parts of our 32 bit word
; are in sreg+1, sreg, X, A.
; Save A and X
stx tmp1
sta tmp2
; Invert high word
lda sreg+1
ldx sreg
; Invert low word
ldy tmp1
sty sreg
ldy tmp2
sty sreg+1
rts

16
libsrc/common/ntohs.s Normal file
View File

@ -0,0 +1,16 @@
;
; Colin Leroy-Mira <colin@colino.net>, 2023-09-06
;
; int __fastcall__ ntohs (int val);
;
.export _ntohs, _htons
.importzp tmp1
_htons := _ntohs
_ntohs:
sta tmp1
txa
ldx tmp1
rts

View File

@ -8,28 +8,46 @@
.export _cputsxy, _cputs
.import gotoxy, _cputc
.importzp ptr1, tmp1
.macpack cpu
_cputsxy:
sta ptr1 ; Save s for later
stx ptr1+1
jsr gotoxy ; Set cursor, pop x and y
.if (.cpu .bitand CPU_ISET_65SC02)
bra L0 ; Same as cputs...
.else
jmp L0 ; Same as cputs...
.endif
_cputs: sta ptr1 ; Save s
stx ptr1+1
L0: ldy #0
L1: lda (ptr1),y
beq L9 ; Jump if done
.if (.cpu .bitand CPU_ISET_65SC02)
L0: lda (ptr1) ; (5)
beq L9 ; (7) Jump if done
jsr _cputc ; (13) Output char, advance cursor
inc ptr1 ; (18) Bump low byte
bne L0 ; (20) Next char
inc ptr1+1 ; (25) Bump high byte
bne L0
.else
L0: ldy #0 ; (2)
L1: lda (ptr1),y ; (7)
beq L9 ; (9) Jump if done
iny
sty tmp1 ; Save offset
jsr _cputc ; Output char, advance cursor
ldy tmp1 ; Get offset
bne L1 ; Next char
inc ptr1+1 ; Bump high byte
sty tmp1 ; (14) Save offset
jsr _cputc ; (20) Output char, advance cursor
ldy tmp1 ; (23) Get offset
bne L1 ; (25) Next char
inc ptr1+1 ; (30) Bump high byte
bne L1
.endif
; Done
L9: rts

View File

@ -10,7 +10,7 @@
.importzp sp, ptr1, ptr2, ptr3, tmp1
.macpack generic
.macpack cpu
.data
@ -74,21 +74,40 @@ out: jsr popax ; count
; Loop outputting characters
.if (.cpu .bitand CPU_ISET_65SC02)
@L1: dec outdesc+6
beq @L4
@L2: ldy tmp1
lda (ptr1),y
iny
bne @L3
inc ptr1+1
@L3: sty tmp1
jsr _cputc
jmp @L1
@L2: lda (ptr1) ; (5)
inc ptr1 ; (10)
bne @L3 ; (12)
inc ptr1+1 ; (17)
@L3: jsr _cputc ; (23)
bra @L1 ; (26)
@L4: dec outdesc+7
bne @L2
rts
.else
@L1: dec outdesc+6
beq @L4
@L2: ldy tmp1 ; (3)
lda (ptr1),y ; (8)
iny ; (10)
bne @L3 ; (12)
inc ptr1+1 ; (17)
@L3: sty tmp1 ; (20)
jsr _cputc ; (26)
jmp @L1 ; (32)
@L4: dec outdesc+7
bne @L2
rts
.endif
; ----------------------------------------------------------------------------
; vcprintf - formatted console i/o
;

View File

@ -95,12 +95,6 @@ IS_UPPER:
BAD_CHAR:
jmp plot
;-----------------------------------------------------------------------------
; Initialize the conio subsystem. "INIT" segment is nothing special on the
; Creativision, it is part of the "ROM" memory.
.segment "INIT"
initconio:
lda #$0
sta SCREEN_PTR

View File

@ -15,7 +15,6 @@
sta $FA ; Middle display data
jsr popa
sta $FB ; Leftmost display data
jsr SCANDS
rts
jmp SCANDS
.endproc

View File

@ -12,10 +12,6 @@
.global __iodir: zp
.global __viddma: zp
.global __sprsys: zp
.global _abc_score_ptr0: zp
.global _abc_score_ptr1: zp
.global _abc_score_ptr2: zp
.global _abc_score_ptr3: zp
.global _FileEntry: zp
.global _FileStartBlock: zp
.global _FileBlockOffset: zp
@ -25,6 +21,3 @@
.global _FileCurrBlock: zp
.global _FileBlockByte: zp
.global _FileDestPtr: zp

View File

@ -16,13 +16,6 @@ __iodir: .res 1
__viddma: .res 1
__sprsys: .res 1
; ------------------------------------------------------------------------
; sound effect pointers for multitimbral Lynx music hardware
_abc_score_ptr0: .res 2
_abc_score_ptr1: .res 2
_abc_score_ptr2: .res 2
_abc_score_ptr3: .res 2
; ------------------------------------------------------------------------
; Filesystem variables needed for reading stuff from the Lynx cart
_FileEntry: ; The file directory entry is 8 bytes
@ -35,4 +28,3 @@ _FileFileLen: .res 2
_FileCurrBlock: .res 1
_FileBlockByte: .res 2
_FileDestPtr: .res 2

View File

@ -252,15 +252,10 @@ InvBaud:
;
SER_GET:
ldx SendFreeCnt ; Send data if necessary
inx ; X == $FF?
beq @L1
lda #$00
jsr TryToSend
; Check for buffer empty
@L1: lda RecvFreeCnt ; (25)
lda RecvFreeCnt ; (25)
cmp #$ff
bne @L2
lda #SER_ERR_NO_DATA
@ -300,21 +295,23 @@ SER_PUT:
; Try to send
ldx SendFreeCnt
inx ; X = $ff?
cpx #$ff ; Nothing to flush
beq @L2
pha
lda #$00
jsr TryToSend
pla
; Put byte into send buffer & send
; Reload SendFreeCnt after TryToSend
@L2: ldx SendFreeCnt
bne @L3
ldx SendFreeCnt
bne @L2
lda #SER_ERR_OVERFLOW ; X is already zero
rts
@L3: ldx SendTail
; Put byte into send buffer & send
@L2: ldx SendTail
sta SendBuf,x
inc SendTail
dec SendFreeCnt
@ -387,25 +384,25 @@ SER_IRQ:
sta tmp1 ; Remember tryHard flag
@L0: lda SendFreeCnt
cmp #$ff
beq @L3 ; Bail out
beq @L2 ; Bail out
; Check for flow stopped
@L1: lda Stopped
bne @L3 ; Bail out
bne @L2 ; Bail out
; Check that swiftlink is ready to send
@L2: lda ACIA_STATUS
lda ACIA_STATUS
and #$10
bne @L4
bne @L3
bit tmp1 ;keep trying if must try hard
bmi @L0
@L3: rts
bmi @L1
@L2: rts
; Send byte and try again
@L4: ldx SendHead
@L3: ldx SendHead
lda SendBuf,x
sta ACIA_DATA
inc SendHead

View File

@ -7,6 +7,7 @@
.import return0, ser_libref
.importzp ptr1
.interruptor ser_irq, 29 ; Export as high priority IRQ handler
.destructor _ser_uninstall
.include "ser-kernel.inc"
.include "ser-error.inc"
@ -44,7 +45,16 @@ ser_sig: .byte $73, $65, $72, SER_API_VERSION ; "ser", version
_ser_install:
sta _ser_drv
ldy _ser_drv ; Check no driver is installed
bne ErrInstalled
ldy _ser_drv+1
beq :+
ErrInstalled:
ldx #$00
lda #SER_ERR_INSTALLED
rts
: sta _ser_drv
sta ptr1
stx _ser_drv+1
stx ptr1+1
@ -107,7 +117,14 @@ copy: lda (ptr1),y
; */
_ser_uninstall:
jsr ser_uninstall ; Call driver routine
ldx _ser_drv ; Check a driver is installed
bne :+
ldx _ser_drv+1
bne :+
lda #SER_ERR_NO_DRIVER
rts
: jsr ser_uninstall ; Call driver routine
lda #$60 ; RTS opcode
sta ser_irq ; Disable IRQ entry point
@ -117,5 +134,6 @@ _ser_clear_ptr: ; External entry point
sta _ser_drv
sta _ser_drv+1 ; Clear the driver pointer
done:
tax
rts ; Return zero

View File

@ -1618,7 +1618,7 @@ static void PutJMP (const InsDesc* Ins)
if (EvalEA (Ins, &A)) {
/* Check for indirect addressing */
if ((A.AddrModeBit & AM65_ABS_IND) && (CPU < CPU_65SC02)) {
if ((A.AddrModeBit & AM65_ABS_IND) && (CPU < CPU_65SC02) && (RelaxChecks == 0)) {
/* Compare the low byte of the expression to 0xFF to check for
** a page cross. Be sure to use a copy of the expression otherwise
@ -1631,7 +1631,7 @@ static void PutJMP (const InsDesc* Ins)
unsigned Msg = GetStringId ("\"jmp (abs)\" across page border");
/* Generate the assertion */
AddAssertion (E, ASSERT_ACT_WARN, Msg);
AddAssertion (E, ASSERT_ACT_ERROR, Msg);
}
/* No error, output code */

View File

@ -21,6 +21,7 @@
<TreatWarningAsError>true</TreatWarningAsError>
<PreprocessorDefinitions>_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;_WIN32_WINNT=0x0601;WINVER=0x0601;NTDDI_VERSION=0x06010000;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories Condition="$(MSBuildProjectName) != 'common'">common</AdditionalIncludeDirectories>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<AdditionalDependencies Condition="$(MSBuildProjectName) != 'common'">$(IntDir)..\..\common\$(Configuration)\common.lib</AdditionalDependencies>
@ -42,13 +43,13 @@
<!-- Release settings. -->
<PropertyGroup Condition="'$(Configuration)'=='Release'">
<LinkIncremental>false</LinkIncremental>
<WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
<ClCompile>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<Optimization>MaxSpeed</Optimization>
<WholeProgramOptimization>true</WholeProgramOptimization>
<BufferSecurityCheck>false</BufferSecurityCheck>
<ControlFlowGuard>false</ControlFlowGuard>
</ClCompile>
@ -57,6 +58,7 @@
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
<AdditionalOptions>/EMITTOOLVERSIONINFO:NO /NOVCFEATURE /NOCOFFGRPINFO %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
</Project>

View File

@ -110,6 +110,7 @@
<ClInclude Include="cc65\scanner.h" />
<ClInclude Include="cc65\scanstrbuf.h" />
<ClInclude Include="cc65\segments.h" />
<ClInclude Include="cc65\seqpoint.h" />
<ClInclude Include="cc65\shiftexpr.h" />
<ClInclude Include="cc65\stackptr.h" />
<ClInclude Include="cc65\standard.h" />
@ -190,6 +191,7 @@
<ClCompile Include="cc65\scanner.c" />
<ClCompile Include="cc65\scanstrbuf.c" />
<ClCompile Include="cc65\segments.c" />
<ClCompile Include="cc65\seqpoint.c" />
<ClCompile Include="cc65\shiftexpr.c" />
<ClCompile Include="cc65\stackptr.c" />
<ClCompile Include="cc65\standard.c" />

View File

@ -65,6 +65,7 @@
#include "preproc.h"
#include "standard.h"
#include "staticassert.h"
#include "typecmp.h"
#include "symtab.h"
@ -178,7 +179,7 @@ static void Parse (void)
** or semicolon, it must be followed by a function body.
*/
if ((Decl.StorageClass & SC_FUNC) != 0) {
if (CurTok.Tok != TOK_COMMA && CurTok.Tok != TOK_SEMI) {
if (CurTok.Tok == TOK_LCURLY) {
/* A definition */
Decl.StorageClass |= SC_DEF;
@ -190,6 +191,10 @@ static void Parse (void)
FuncDef->Flags = (FuncDef->Flags & ~FD_EMPTY) | FD_VOID_PARAM;
}
} else {
if (CurTok.Tok != TOK_COMMA && CurTok.Tok != TOK_SEMI) {
Error ("Expected ',' or ';' after top level declarator");
}
/* Just a declaration */
Decl.StorageClass |= SC_DECL;
}
@ -321,17 +326,24 @@ static void Parse (void)
if (Sym && IsTypeFunc (Sym->Type)) {
/* Function */
if (!comma) {
if (CurTok.Tok == TOK_SEMI) {
/* Prototype only */
NextToken ();
} else {
/* Parse the function body */
NewFunc (Sym, FuncDef);
/* Make sure we aren't omitting any work */
CheckDeferredOpAllDone ();
if (CurTok.Tok == TOK_SEMI) {
/* Prototype only */
NextToken ();
} else if (CurTok.Tok == TOK_LCURLY) {
/* ISO C: The type category in a function definition cannot be
** inherited from a typedef.
*/
if (IsTypeFunc (Spec.Type) && TypeCmp (Sym->Type, Spec.Type).C >= TC_EQUAL) {
Error ("Function cannot be defined with a typedef");
} else if (comma) {
Error ("';' expected after top level declarator");
}
/* Parse the function body anyways */
NewFunc (Sym, FuncDef);
/* Make sure we aren't omitting any work */
CheckDeferredOpAllDone ();
}
} else {

View File

@ -515,6 +515,13 @@ static void CheckArrayElementType (Type* DataType)
if (!IsTypeVoid (T) || IS_Get (&Standard) != STD_CC65) {
Error ("Array of 0-size element type '%s'", GetFullTypeName (T));
}
} else {
if (IsTypeStruct (T)) {
SymEntry* TagEntry = GetESUTagSym (T);
if (TagEntry && SymHasFlexibleArrayMember (TagEntry)) {
Error ("Invalid use of struct with flexible array member");
}
}
}
} else {
++T;
@ -1193,6 +1200,9 @@ static SymEntry* ParseStructSpec (const char* Name, unsigned* DSFlags)
if (TagEntry && SymHasFlexibleArrayMember (TagEntry)) {
Field->Flags |= SC_HAVEFAM;
Flags |= SC_HAVEFAM;
if (IsTypeStruct (Decl.Type)) {
Error ("Invalid use of struct with flexible array member");
}
}
}
@ -1452,7 +1462,7 @@ static void ParseTypeSpec (DeclSpec* D, typespec_t TSFlags, int* SignednessSpeci
NextToken ();
} else {
if (CurTok.Tok != TOK_LCURLY) {
Error ("Identifier expected");
Error ("Identifier expected for enum tag name");
}
AnonName (Ident, "enum");
}
@ -1504,8 +1514,8 @@ static void ParseTypeSpec (DeclSpec* D, typespec_t TSFlags, int* SignednessSpeci
/* FALL THROUGH */
default:
if ((TSFlags & TS_MASK_DEFAULT_TYPE) != TS_DEFAULT_TYPE_INT) {
Error ("Type expected");
if ((TSFlags & TS_MASK_DEFAULT_TYPE) == TS_DEFAULT_TYPE_NONE) {
D->Flags |= DS_NO_TYPE;
D->Type[0].C = T_INT;
D->Type[1].C = T_END;
} else {
@ -1553,8 +1563,7 @@ static const Type* ParamTypeCvt (Type* T)
static void ParseOldStyleParamList (FuncDesc* F)
/* Parse an old-style (K&R) parameter list */
{
/* Some fix point tokens that are used for error recovery */
static const token_t TokenList[] = { TOK_COMMA, TOK_RPAREN, TOK_SEMI };
unsigned PrevErrorCount = ErrorCount;
/* Parse params */
while (CurTok.Tok != TOK_RPAREN) {
@ -1572,8 +1581,11 @@ static void ParseOldStyleParamList (FuncDesc* F)
NextToken ();
} else {
/* Some fix point tokens that are used for error recovery */
static const token_t TokenList[] = { TOK_COMMA, TOK_RPAREN, TOK_SEMI };
/* Not a parameter name */
Error ("Identifier expected");
Error ("Identifier expected for parameter name");
/* Try some smart error recovery */
SkipTokens (TokenList, sizeof(TokenList) / sizeof(TokenList[0]));
@ -1608,6 +1620,12 @@ static void ParseOldStyleParamList (FuncDesc* F)
Error ("Illegal storage class");
}
/* Type must be specified */
if ((Spec.Flags & DS_NO_TYPE) != 0) {
Error ("Expected declaration specifiers");
break;
}
/* Parse a comma separated variable list */
while (1) {
@ -1655,6 +1673,14 @@ static void ParseOldStyleParamList (FuncDesc* F)
/* Variable list must be semicolon terminated */
ConsumeSemi ();
}
if (PrevErrorCount != ErrorCount) {
/* Some fix point tokens that are used for error recovery */
static const token_t TokenList[] = { TOK_COMMA, TOK_SEMI };
/* Try some smart error recovery */
SkipTokens (TokenList, sizeof(TokenList) / sizeof(TokenList[0]));
}
}
@ -1689,6 +1715,11 @@ static void ParseAnsiParamList (FuncDesc* F)
Spec.StorageClass = SC_AUTO | SC_PARAM | SC_DEF;
}
/* Type must be specified */
if ((Spec.Flags & DS_NO_TYPE) != 0) {
Error ("Type specifier missing");
}
/* Warn about new local type declaration */
if ((Spec.Flags & DS_NEW_TYPE_DECL) != 0) {
Warning ("'%s' will be invisible out of this function",
@ -1870,12 +1901,21 @@ static void DirectDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode)
} else {
if (Mode == DM_NEED_IDENT) {
/* Some fix point tokens that are used for error recovery */
static const token_t TokenList[] = { TOK_COMMA, TOK_SEMI };
static const token_t TokenList[] = { TOK_COMMA, TOK_SEMI, TOK_LCURLY, TOK_RCURLY };
Error ("Identifier expected");
/* Try some smart error recovery */
SkipTokens (TokenList, sizeof(TokenList) / sizeof(TokenList[0]));
/* Skip curly braces */
if (CurTok.Tok == TOK_LCURLY) {
static const token_t CurlyToken[] = { TOK_RCURLY };
SkipTokens (CurlyToken, sizeof(CurlyToken) / sizeof(CurlyToken[0]));
NextToken ();
} else if (CurTok.Tok == TOK_RCURLY) {
NextToken ();
}
}
D->Ident[0] = '\0';
}

View File

@ -71,8 +71,9 @@ enum typespec_t {
/* Masks for the Flags field in DeclSpec */
#define DS_DEF_STORAGE 0x0001U /* Default storage class used */
#define DS_DEF_TYPE 0x0002U /* Default type used */
#define DS_EXTRA_TYPE 0x0004U /* Extra type declared */
#define DS_NO_TYPE 0x0002U /* No type explicitly specified */
#define DS_DEF_TYPE 0x0006U /* Default type used */
#define DS_EXTRA_TYPE 0x0008U /* Extra type declared */
#define DS_NEW_TYPE_DECL 0x0010U /* New type declared */
#define DS_NEW_TYPE_DEF 0x0020U /* New type defined */
#define DS_NEW_TYPE (DS_NEW_TYPE_DECL | DS_NEW_TYPE_DEF)

View File

@ -31,6 +31,7 @@
#include "macrotab.h"
#include "preproc.h"
#include "scanner.h"
#include "seqpoint.h"
#include "shiftexpr.h"
#include "stackptr.h"
#include "standard.h"
@ -691,6 +692,7 @@ void DoDeferred (unsigned Flags, ExprDesc* Expr)
int I;
unsigned Size = 0;
int Count = GetDeferredOpCount ();
unsigned StmtFlags = GetSQPFlags ();
/* Nothing to be done */
if (Count <= 0) {
@ -698,26 +700,38 @@ void DoDeferred (unsigned Flags, ExprDesc* Expr)
}
/* Backup some regs/processor flags around the inc/dec */
if ((Flags & SQP_KEEP_TEST) != 0 && ED_NeedsTest (Expr)) {
if ((StmtFlags & SQP_KEEP_TEST) != 0 ||
((Flags & SQP_KEEP_TEST) != 0 && ED_NeedsTest (Expr))) {
/* Sufficient to add a pair of PHP/PLP for all cases */
AddCodeLine ("php");
}
/* Backup the content of EAX around the inc/dec */
if ((Flags & SQP_KEEP_EAX) != 0 && ED_NeedsPrimary (Expr)) {
/* Get the size */
Size = CheckedSizeOf (Expr->Type);
if ((Flags & SQP_MASK_EAX) != 0 && ED_NeedsPrimary (Expr)) {
Size = SizeOf (Expr->Type);
}
if (Size < 2) {
AddCodeLine ("pha");
} else if (Size < 3) {
AddCodeLine ("sta regsave");
AddCodeLine ("stx regsave+1");
} else {
AddCodeLine ("jsr saveeax");
/* Get the size of the backup */
if ((StmtFlags & SQP_MASK_EAX) != 0) {
switch (StmtFlags & SQP_MASK_EAX) {
case SQP_KEEP_A: if (Size < 1) Size = 1; break;
case SQP_KEEP_AX: if (Size < 2) Size = 2; break;
case SQP_KEEP_EAX: if (Size < 4) Size = 4; break;
default: ;
}
}
/* Backup the content of EAX around the inc/dec */
if (Size == 1) {
AddCodeLine ("pha");
} else if (Size == 2) {
AddCodeLine ("sta regsave");
AddCodeLine ("stx regsave+1");
} else if (Size == 3 || Size == 4) {
AddCodeLine("jsr saveeax");
} else if (Size > 4) {
Error ("Unsupported deferred operand size: %u", Size);
}
for (I = 0; I < Count; ++I) {
DeferredOp* Op = CollAtUnchecked (&DeferredOps, I);
switch (Op->OpType) {
@ -735,19 +749,18 @@ void DoDeferred (unsigned Flags, ExprDesc* Expr)
CollDeleteAll (&DeferredOps);
/* Restore the content of EAX around the inc/dec */
if ((Flags & SQP_KEEP_EAX) != 0 && ED_NeedsPrimary (Expr)) {
if (Size < 2) {
AddCodeLine ("pla");
} else if (Size < 3) {
AddCodeLine ("lda regsave");
AddCodeLine ("ldx regsave+1");
} else {
AddCodeLine ("jsr resteax");
}
if (Size == 1) {
AddCodeLine ("pla");
} else if (Size == 2) {
AddCodeLine ("lda regsave");
AddCodeLine ("ldx regsave+1");
} else if (Size == 3 || Size == 4) {
AddCodeLine ("jsr resteax");
}
/* Restore the regs/processor flags around the inc/dec */
if ((Flags & SQP_KEEP_TEST) != 0 && ED_NeedsTest (Expr)) {
if ((StmtFlags & SQP_KEEP_TEST) != 0 ||
((Flags & SQP_KEEP_TEST) != 0 && ED_NeedsTest (Expr))) {
/* Sufficient to pop the processor flags */
AddCodeLine ("plp");
}
@ -1049,6 +1062,10 @@ static void FunctionCall (ExprDesc* Expr)
/* Parse the argument list and pass them to the called function */
ArgSize = FunctionArgList (Func, IsFastcall, Expr);
if (ArgSize > 0xFF && (Func->Flags & FD_VARIADIC) != 0) {
Error ("Total size of all arguments passed to a variadic function cannot exceed 255 bytes");
}
/* We need the closing paren here */
ConsumeRParen ();
@ -1372,6 +1389,7 @@ static void Primary (ExprDesc* E)
case TOK_A:
/* Register pseudo variable */
SetSQPFlags (SQP_KEEP_A);
E->Type = type_uchar;
E->Flags = E_LOC_PRIMARY | E_RTYPE_LVAL;
NextToken ();
@ -1379,6 +1397,7 @@ static void Primary (ExprDesc* E)
case TOK_AX:
/* Register pseudo variable */
SetSQPFlags (SQP_KEEP_AX);
E->Type = type_uint;
E->Flags = E_LOC_PRIMARY | E_RTYPE_LVAL;
NextToken ();
@ -1386,6 +1405,7 @@ static void Primary (ExprDesc* E)
case TOK_EAX:
/* Register pseudo variable */
SetSQPFlags (SQP_KEEP_EAX);
E->Type = type_ulong;
E->Flags = E_LOC_PRIMARY | E_RTYPE_LVAL;
NextToken ();
@ -1453,7 +1473,7 @@ static void StructRef (ExprDesc* Expr)
/* Skip the token and check for an identifier */
NextToken ();
if (CurTok.Tok != TOK_IDENT) {
Error ("Identifier expected");
Error ("Identifier expected for %s member", GetBasicTypeName (Expr->Type));
/* Make the expression an integer at address zero */
ED_MakeConstAbs (Expr, 0, type_int);
return;

View File

@ -23,11 +23,6 @@
#define SQP_KEEP_NONE 0x00
#define SQP_KEEP_TEST 0x01U
#define SQP_KEEP_EAX 0x02U
#define SQP_KEEP_EXPR 0x03U /* SQP_KEEP_TEST | SQP_KEEP_EAX */
/* Generator attributes */
#define GEN_NOPUSH 0x01 /* Don't push lhs */
#define GEN_COMM 0x02 /* Operator is commutative */

View File

@ -43,6 +43,7 @@
#include "expr.h"
#include "loadexpr.h"
#include "scanner.h"
#include "seqpoint.h"
#include "standard.h"
#include "symtab.h"
#include "goto.h"

View File

@ -59,6 +59,7 @@
#include "litpool.h"
#include "pragma.h"
#include "scanner.h"
#include "seqpoint.h"
#include "shift.h"
#include "standard.h"
#include "symtab.h"
@ -365,8 +366,8 @@ static unsigned ParseArrayInit (Type* T, int* Braces, int AllowFlexibleMembers)
/* Char array initialized by string constant */
int NeedParen;
/* If we initializer is enclosed in brackets, remember this fact and
** skip the opening bracket.
/* If the initializer is enclosed in curly braces, remember this fact
** and skip the opening one.
*/
NeedParen = (CurTok.Tok == TOK_LCURLY);
if (NeedParen) {
@ -399,7 +400,9 @@ static unsigned ParseArrayInit (Type* T, int* Braces, int AllowFlexibleMembers)
} else {
/* Arrays can be initialized without a pair of curly braces */
/* An array can be initialized without a pair of enclosing curly braces
** if it is itself a member of a struct/union or an element of an array.
*/
if (*Braces == 0 || CurTok.Tok == TOK_LCURLY) {
/* Consume the opening curly brace */
HasCurly = ConsumeLCurly ();
@ -409,14 +412,22 @@ static unsigned ParseArrayInit (Type* T, int* Braces, int AllowFlexibleMembers)
/* Initialize the array members */
Count = 0;
while (CurTok.Tok != TOK_RCURLY) {
/* Flexible array members may not be initialized within
** an array (because the size of each element may differ
** otherwise).
/* Flexible array members cannot be initialized within an array.
** (Otherwise the size of each element may differ.)
*/
ParseInitInternal (ElementType, Braces, 0);
++Count;
if (CurTok.Tok != TOK_COMMA)
if (CurTok.Tok != TOK_COMMA) {
break;
}
if (!HasCurly && ElementCount > 0 && Count >= ElementCount) {
/* If the array is initialized without enclosing curly braces,
** it only accepts how many elements initializers up to its
** count of elements, leaving any following initializers out.
*/
break;
}
NextToken ();
}
@ -513,7 +524,7 @@ static unsigned ParseStructInit (Type* T, int* Braces, int AllowFlexibleMembers)
Error ("Excess elements in %s initializer", GetBasicTypeName (T));
SkipInitializer (HasCurly);
}
return SI.Offs;
break;
}
/* Check for special members that don't consume the initializer */

View File

@ -49,6 +49,7 @@
#include "initdata.h"
#include "loadexpr.h"
#include "locals.h"
#include "seqpoint.h"
#include "stackptr.h"
#include "standard.h"
#include "staticassert.h"

67
src/cc65/seqpoint.c Normal file
View File

@ -0,0 +1,67 @@
/*****************************************************************************/
/* */
/* seqpoint.h */
/* */
/* Stuff involved in sequence points */
/* */
/* */
/* */
/* Copyright 2022 The cc65 Authors */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
/* cc65 */
#include "seqpoint.h"
/*****************************************************************************/
/* data */
/*****************************************************************************/
/* Remeber if __A__, __AX__ and __EAX__ are being used */
unsigned PendingSqpFlags = SQP_KEEP_NONE;
/*****************************************************************************/
/* code */
/*****************************************************************************/
void SetSQPFlags (unsigned Flags)
/* Set the SQP_KEEP_* flags for the deferred operations in the statement */
{
PendingSqpFlags = Flags;
}
unsigned GetSQPFlags (void)
/* Get the SQP_KEEP_* flags for the deferred operations in the statement */
{
return PendingSqpFlags;
}

70
src/cc65/seqpoint.h Normal file
View File

@ -0,0 +1,70 @@
/*****************************************************************************/
/* */
/* seqpoint.h */
/* */
/* Stuff involved in sequence points */
/* */
/* */
/* */
/* Copyright 2022 The cc65 Authors */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#ifndef SEQPOINT_H
#define SEQPOINT_H
/*****************************************************************************/
/* data */
/*****************************************************************************/
#define SQP_KEEP_NONE 0x00U
#define SQP_KEEP_A 0x01U
#define SQP_KEEP_AX 0x03U
#define SQP_KEEP_EAX 0x07U
#define SQP_MASK_EAX 0x07U
#define SQP_KEEP_TEST 0x10U
#define SQP_KEEP_EXPR 0x17U /* SQP_KEEP_TEST | SQP_KEEP_EAX */
/*****************************************************************************/
/* code */
/*****************************************************************************/
void SetSQPFlags (unsigned Flags);
/* Set the SQP_KEEP_* flags for the deferred operations in the statement */
unsigned GetSQPFlags (void);
/* Get the SQP_KEEP_* flags for the deferred operations in the statement */
/* End of seqpoint.h */
#endif

View File

@ -50,6 +50,7 @@
#include "litpool.h"
#include "loadexpr.h"
#include "scanner.h"
#include "seqpoint.h"
#include "stackptr.h"
#include "stdfunc.h"
#include "stdnames.h"

View File

@ -56,6 +56,7 @@
#include "loop.h"
#include "pragma.h"
#include "scanner.h"
#include "seqpoint.h"
#include "stackptr.h"
#include "stmt.h"
#include "swstmt.h"
@ -674,6 +675,8 @@ int AnyStatement (int* PendingToken)
** NULL, the function will skip the token.
*/
{
int GotBreak = 0;
/* Assume no pending token */
if (PendingToken) {
*PendingToken = 0;
@ -689,7 +692,8 @@ int AnyStatement (int* PendingToken)
switch (CurTok.Tok) {
case TOK_IF:
return IfStatement ();
GotBreak = IfStatement ();
break;
case TOK_SWITCH:
SwitchStatement ();
@ -710,22 +714,26 @@ int AnyStatement (int* PendingToken)
case TOK_GOTO:
GotoStatement ();
CheckSemi (PendingToken);
return 1;
GotBreak = 1;
break;
case TOK_RETURN:
ReturnStatement ();
CheckSemi (PendingToken);
return 1;
GotBreak = 1;
break;
case TOK_BREAK:
BreakStatement ();
CheckSemi (PendingToken);
return 1;
GotBreak = 1;
break;
case TOK_CONTINUE:
ContinueStatement ();
CheckSemi (PendingToken);
return 1;
GotBreak = 1;
break;
case TOK_PRAGMA:
DoPragma ();
@ -737,12 +745,17 @@ int AnyStatement (int* PendingToken)
break;
case TOK_LCURLY:
return CompoundStatement (PendingToken);
GotBreak = CompoundStatement (PendingToken);
break;
default:
/* Simple statement */
Statement (PendingToken);
break;
}
return 0;
/* Reset SQP flags */
SetSQPFlags (SQP_KEEP_NONE);
return GotBreak;
}

View File

@ -1225,6 +1225,15 @@ SymEntry* AddLocalSym (const char* Name, const Type* T, unsigned Flags, int Offs
/* Do we have an entry with this name already? */
SymEntry* Entry = FindSymInTable (Tab, Name, HashStr (Name));
if (Entry) {
int CheckExtern = 0;
if ((Flags & SC_STRUCTFIELD) == 0) {
while (Entry && (Entry->Flags & SC_ALIAS) == SC_ALIAS) {
/* Get the aliased entry */
Entry = Entry->V.A.Field;
/* Check for conflict with local storage class */
CheckExtern = 1;
}
}
/* We have a symbol with this name already */
if (HandleSymRedefinition (Entry, T, Flags)) {
@ -1234,19 +1243,14 @@ SymEntry* AddLocalSym (const char* Name, const Type* T, unsigned Flags, int Offs
if (SymIsDef (Entry) && (Flags & SC_DEF) == SC_DEF) {
Error ("Multiple definition of '%s'", Entry->Name);
Entry = 0;
} else if ((Flags & (SC_AUTO | SC_REGISTER)) != 0 &&
(Entry->Flags & SC_EXTERN) != 0) {
/* Check for local storage class conflict */
Error ("Declaration of '%s' with no linkage follows extern declaration",
Name);
Entry = 0;
} else {
/* If a static declaration follows a non-static declaration,
** then it is an error.
*/
if ((Flags & SC_DEF) &&
(Flags & SC_EXTERN) == 0 &&
(Entry->Flags & SC_EXTERN) != 0) {
} else if (CheckExtern) {
if ((Flags & (SC_AUTO | SC_REGISTER)) != 0) {
Error ("Declaration of '%s' with no linkage follows extern declaration", Name);
Entry = 0;
} else if ((Flags & SC_DEF) != 0 && (Flags & SC_EXTERN) == 0) {
/* If a static declaration follows a non-static declaration,
** then it is an error.
*/
Error ("Static declaration of '%s' follows extern declaration", Name);
Entry = 0;
}
@ -1340,7 +1344,8 @@ SymEntry* AddGlobalSym (const char* Name, const Type* T, unsigned Flags)
Name);
Entry = 0;
} else if ((Flags & SC_ESUTYPEMASK) != SC_TYPEDEF) {
/* If a static declaration follows a non-static declaration, then the result is undefined.
/* If a static declaration follows a non-static declaration, then
** the result is undefined.
** Most compilers choose to either give an error at compile time,
** or remove the extern property for a link time error if used.
*/
@ -1348,6 +1353,7 @@ SymEntry* AddGlobalSym (const char* Name, const Type* T, unsigned Flags)
(Flags & SC_EXTERN) == 0 &&
(Entry->Flags & SC_EXTERN) != 0) {
Error ("Static declaration of '%s' follows non-static declaration", Name);
Entry = 0;
} else if ((Flags & SC_EXTERN) != 0 &&
(Entry->Owner == SymTab0 || (Entry->Flags & SC_DEF) != 0) &&
(Entry->Flags & SC_EXTERN) == 0) {
@ -1359,14 +1365,15 @@ SymEntry* AddGlobalSym (const char* Name, const Type* T, unsigned Flags)
*/
if (Entry->Owner == SymTab0) {
if ((Flags & SC_STORAGE) == 0) {
/* Linkage must be unchanged.
** The C standard specifies that a later extern declaration will be ignored,
** and will use the previous linkage instead. Giving a warning for this case.
/* The C standard specifies that a later extern declaration will keep
** the previously declared internal or external linkage unchanged.
** Though not required by the standard, we are warning on this case.
*/
Flags &= ~SC_EXTERN;
Warning ("Extern declaration of '%s' follows static declaration, extern ignored", Name);
Warning ("Extern declaration of '%s' follows static declaration, linkage unchanged", Name);
} else {
Error ("Non-static declaration of '%s' follows static declaration", Name);
Entry = 0;
}
} else {
Error ("Extern declaration of '%s' follows static declaration", Name);

View File

@ -39,6 +39,7 @@
#include "expr.h"
#include "loadexpr.h"
#include "scanner.h"
#include "seqpoint.h"
#include "testexpr.h"

View File

@ -1,18 +1,23 @@
@echo off
setlocal
if exist "C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\Common7\Tools\VsDevCmd.bat" goto vs2017
if exist "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\Tools\VsDevCmd.bat" goto vs2019
where msbuild.exe 1>nul 2>&1 && goto :ready
echo Error: VsDevCmd.bat not found!
goto:eof
set VSWHERE_PATH=%ProgramFiles%\Microsoft Visual Studio\Installer\vswhere.exe
if not exist "%VSWHERE_PATH%" set VSWHERE_PATH=%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe
if not exist "%VSWHERE_PATH%" goto :error
for /f "usebackq delims=#" %%a in (`"%VSWHERE_PATH%" -latest -property installationPath`) do set VSDEVCMD_PATH=%%a\Common7\Tools\VsDevCmd.bat
if not exist "%VSDEVCMD_PATH%" goto :error
set VSCMD_SKIP_SENDTELEMETRY=1
call "%VSDEVCMD_PATH%" -no_logo -startdir=none
:vs2017
call "C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\Common7\Tools\VsDevCmd.bat"
goto run
where msbuild.exe 1>nul 2>&1 && goto :ready
:vs2019
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\Tools\VsDevCmd.bat"
goto run
:error
echo Error: Can't find MSBuild.
exit /b 1
:ready
:run
msbuild.exe %*

View File

@ -0,0 +1,4 @@
; test that jmp (indirect) on a page boundary will give an error for 6502 CPU
.p02
jmp ($10FF)

View File

@ -0,0 +1,18 @@
; test that jmp (indirect) on a page boundary will not give an error for non-6502 CPUs
.pc02
jmp ($10FF)
.psc02
jmp ($10FF)
.p816
jmp ($10FF)
; main always returns success (the tested issue is only whether the assembly errors)
.import _exit
.export _main
_main:
lda #0
tax
jmp _exit

View File

@ -0,0 +1,11 @@
/* Bug #2016 - cc65 erroneously allows struct fields that are structs with flexible array members */
typedef struct x {
int a;
int b[]; /* Ok: Flexible array member can be last */
} x;
struct y {
x x; /* Not ok: Contains flexible array member */
int a;
};

View File

@ -0,0 +1,9 @@
/* Bug #2017 - cc65 erroneously allows arrays of structs with flexible array members */
struct z {
int a;
int c;
int b[];
};
struct z y[3]; /* Should be an error */

View File

@ -0,0 +1,6 @@
/* Bug #2020 - ISO/IEC 9899:1999 (E), 6.9.1 footnote 137:
** "The intent is that the type category in a function definition cannot be inherited from a typedef"
*/
typedef void F(void);
F c { } /* Should fail */

13
test/err/bug2144.c Normal file
View File

@ -0,0 +1,13 @@
/* Bug #2144 - Maximum parameter size is not checked for variadic functions */
void a(...) {}
void b()
{
/* Argument size > 255 */
a(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L);
}

View File

@ -0,0 +1,8 @@
/* Bug #2162 - conflicting declarations in functions */
int main(void)
{
extern int i;
int i = 42; /* Error */
return i;
}

View File

@ -0,0 +1,8 @@
/* Bug #2162 - conflicting declarations in functions */
int main(void)
{
static int i = 42;
extern int i; /* Error */
return i;
}

View File

@ -0,0 +1,10 @@
/* Bug #2162 - conflicting declarations in functions */
static int i;
int main(void)
{
extern int i; /* cc65 allows this */
int i = 42; /* Error - if this were accepted, it would be confusing which object i refers to */
return i;
}

View File

@ -0,0 +1,10 @@
/* Bug #2162 - conflicting declarations in functions */
static int i;
int main(void)
{
static int i = 42; /* OK - this shadows the i in file scope */
extern int i; /* Error - if this were accepted, it would be confusing which object i refers to */
return i;
}

View File

@ -1,3 +1,5 @@
bug1889-missing-identifier.c:3: Error: Identifier expected
bug1889-missing-identifier.c:3: Error: ';' expected
bug1889-missing-identifier.c:3: Warning: Implicit 'int' is an obsolete feature
bug1889-missing-identifier.c:4: Error: Identifier expected
bug1889-missing-identifier.c:4: Warning: Implicit 'int' is an obsolete feature

16
test/val/bug2020-ok.c Normal file
View File

@ -0,0 +1,16 @@
/* Bug #2020 - Right cases */
typedef int F(void); // type F is "function with no parameters returning int"
F f, g; // f and g both have type compatible with F
int f(void) { return 0; } // RIGHT: f has type compatible with F
int g() { return 0; } // RIGHT: g has type compatible with F
F *e(void) { return 0; } // e returns a pointer to a function
F *((h))(void) { return 0; } // similar: parentheses irrelevant
int (*fp)(void); // fp points to a function that has type F
F *Fp; // Fp points to a function that has type
int main(void)
{
return 0;
}

47
test/val/bug2135.c Normal file
View File

@ -0,0 +1,47 @@
/* Bug #2135 - Compound initialization consumes wrong amount of initializers with omitted
** enclosing curly braces when an array/struct/union to initialize is itself
** a member/element of a struct/union/array.
*/
#include <stdint.h>
#include <stdio.h>
struct s {
union {
int8_t a[2][2];
char c[sizeof (int8_t) * 2 * 2 + sizeof (int16_t) * 4];
};
int16_t b[4];
};
struct s x = { 1, 2, 3, 4, 5, 6 };
struct s y = { {{{1, 2}, {3, 4}}}, {5, 6} };
unsigned failures;
int main(void)
{
unsigned i, j;
for (i = 0; i < 2; ++i)
{
for (j = 0; j < 2; ++j)
{
if (x.a[i][j] != y.a[i][j])
{
++failures;
printf("x.a[%u][%u] = %d\n, expected %d\n", i, j, x.a[i][j], y.a[i][j]);
}
}
}
for (i = 0; i < 4; ++i)
{
if (x.b[i] != y.b[i])
{
++failures;
printf("x.b[%u] = %d\n, expected %d\n", i, x.b[i], y.b[i]);
}
}
return failures;
}

View File

@ -1,9 +1,11 @@
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#ifdef __CC65__
#define testasm1(C) (__AX__ = (C), \
asm("and #$3f"),\
__AX__)
@ -11,6 +13,22 @@
#define testasm2(C) (__A__ = (C), \
asm("and #$3f"),\
__A__)
#else
/* Non-cc65 compiler. Just make the code compile and work. */
uint16_t testasm1(uint16_t C)
{
uint16_t AX = C;
AX &= 0x3f;
return AX;
}
uint8_t testasm2(uint8_t C)
{
uint8_t A = C;
A &= 0x3f;
return A;
}
#endif
uint8_t src[32] = { 0x10, 0x41, 0x62, 0x83, 0xb4, 0xf5, 0xe6, 0xc7, 0, 0 };
uint8_t src2[32] = { 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0, 0 };
@ -47,7 +65,7 @@ void dotest1b(uint8_t *s, uint8_t *d)
void dotest2a (void)
{
char *p = &src2[0];
uint16_t scaddr=&dest[0];
uintptr_t scaddr=&dest[0]; //output to line 11 on the screen
printf("dotest2a\n");
while (*p != 0) {
@ -59,7 +77,7 @@ void dotest2a (void)
void dotest2b (void)
{
char *p = &src2[0];
uint16_t scaddr=&dest[0];
uintptr_t scaddr=&dest[0]; //output to line 11 on the screen
printf("dotest2b\n");
while (*p != 0) {

View File

@ -0,0 +1,34 @@
/*
!!DESCRIPTION!! A small test for htons.
!!ORIGIN!!
!!LICENCE!!
!!AUTHOR!! Colin Leroy-Mira
*/
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
static unsigned int Failures = 0;
static void CheckHtonl (long input, long expected)
{
long result = htonl(input);
if (result != expected) {
printf ("htonl error:\n"
" result = %ld for %ld, should be %ld\n", result, input, expected);
++Failures;
}
}
int main (void)
{
CheckHtonl(0x00000000, 0x00000000);
CheckHtonl(0x12345678, 0x78563412);
CheckHtonl(0xAABBCCDD, 0xDDCCBBAA);
CheckHtonl(0xFFFFFFFF, 0xFFFFFFFF);
printf ("Failures: %u\n", Failures);
return Failures;
}

View File

@ -0,0 +1,34 @@
/*
!!DESCRIPTION!! A small test for htons.
!!ORIGIN!!
!!LICENCE!!
!!AUTHOR!! Colin Leroy-Mira
*/
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
static unsigned int Failures = 0;
static void CheckHtons (int input, int expected)
{
int result = htons(input);
if (result != expected) {
printf ("htons error:\n"
" result = %d for %d, should be %d\n", result, input, expected);
++Failures;
}
}
int main (void)
{
CheckHtons(0x0000, 0x0000);
CheckHtons(0x1234, 0x3412);
CheckHtons(0xA0F2, 0xF2A0);
CheckHtons(0xFFFF, 0xFFFF);
printf ("Failures: %u\n", Failures);
return Failures;
}