mirror of
https://github.com/cc65/cc65.git
synced 2024-06-26 20:29:34 +00:00
Merge branch 'master' into fptest
This commit is contained in:
commit
db7a38ea17
15
.editorconfig
Normal file
15
.editorconfig
Normal 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
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 II Super Serial Card. Supports up to 19200 baud,
|
||||
requires hardware flow control (RTS/CTS) and does interrupt driven receives.
|
||||
Driver for the Apple 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 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 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>
|
||||
|
||||
|
|
|
@ -21,7 +21,8 @@ as it comes with the cc65 C compiler. It describes the memory layout,
|
|||
enhanced Apple //e specific header files, available drivers, and any
|
||||
pitfalls specific to that platform.
|
||||
|
||||
Please note that enhanced Apple //e specific functions are just mentioned
|
||||
Please note that this target requires a 65C02 or 65816 CPU,
|
||||
enhanced Apple //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 II Super Serial Card. Supports up to 19200 baud,
|
||||
requires hardware flow control (RTS/CTS) and does interrupt driven receives.
|
||||
Driver for the Apple 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 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 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>
|
||||
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
137
doc/funcref.sgml
137
doc/funcref.sgml
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
67
include/arpa/inet.h
Normal 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
|
|
@ -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 */
|
||||
|
|
|
@ -131,8 +131,8 @@ $(TARGETS): | ../lib
|
|||
|
||||
else # TARGET
|
||||
|
||||
CA65FLAGS =
|
||||
CC65FLAGS = -Or -W error
|
||||
CA65FLAGS = -g
|
||||
CC65FLAGS = -g -Or -W error
|
||||
|
||||
EXTZP = cbm510 \
|
||||
cbm610 \
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
713
libsrc/apple2/ser/a2.gs.s
Normal 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
|
|
@ -26,6 +26,7 @@
|
|||
.include "ser-error.inc"
|
||||
|
||||
.macpack module
|
||||
.macpack cpu
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; Header. Includes jump table
|
||||
|
@ -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,32 +221,31 @@ 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
|
||||
.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
|
||||
bne InvParm
|
||||
|
||||
; Initialize buffers
|
||||
ldy #$00
|
||||
ldy #$00 ; Initialize buffers
|
||||
sty Stopped
|
||||
sty RecvHead
|
||||
sty RecvTail
|
||||
|
@ -229,30 +264,31 @@ SER_OPEN:
|
|||
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
|
||||
|
@ -263,18 +299,18 @@ SER_OPEN:
|
|||
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
32
libsrc/common/ntohl.s
Normal 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
16
libsrc/common/ntohs.s
Normal 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
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
sta $FA ; Middle display data
|
||||
jsr popa
|
||||
sta $FB ; Leftmost display data
|
||||
jsr SCANDS
|
||||
rts
|
||||
jmp SCANDS
|
||||
|
||||
.endproc
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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,18 +326,25 @@ 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 */
|
||||
} 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 {
|
||||
|
||||
|
|
|
@ -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';
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,24 +700,36 @@ 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) {
|
||||
/* 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 < 3) {
|
||||
} else if (Size == 2) {
|
||||
AddCodeLine ("sta regsave");
|
||||
AddCodeLine ("stx regsave+1");
|
||||
} else {
|
||||
} 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) {
|
||||
|
@ -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) {
|
||||
if (Size == 1) {
|
||||
AddCodeLine ("pla");
|
||||
} else if (Size < 3) {
|
||||
} else if (Size == 2) {
|
||||
AddCodeLine ("lda regsave");
|
||||
AddCodeLine ("ldx regsave+1");
|
||||
} else {
|
||||
} 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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
67
src/cc65/seqpoint.c
Normal 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
70
src/cc65/seqpoint.h
Normal 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
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
} else if (CheckExtern) {
|
||||
if ((Flags & (SC_AUTO | SC_REGISTER)) != 0) {
|
||||
Error ("Declaration of '%s' with no linkage follows extern declaration", Name);
|
||||
Entry = 0;
|
||||
} else {
|
||||
} else if ((Flags & SC_DEF) != 0 && (Flags & SC_EXTERN) == 0) {
|
||||
/* 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) {
|
||||
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);
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "expr.h"
|
||||
#include "loadexpr.h"
|
||||
#include "scanner.h"
|
||||
#include "seqpoint.h"
|
||||
#include "testexpr.h"
|
||||
|
||||
|
||||
|
|
|
@ -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 %*
|
||||
|
|
4
test/asm/err/jmp-indirect-6502-error.s
Normal file
4
test/asm/err/jmp-indirect-6502-error.s
Normal file
|
@ -0,0 +1,4 @@
|
|||
; test that jmp (indirect) on a page boundary will give an error for 6502 CPU
|
||||
|
||||
.p02
|
||||
jmp ($10FF)
|
18
test/asm/val/jmp-indirect-success.s
Normal file
18
test/asm/val/jmp-indirect-success.s
Normal 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
|
11
test/err/bug2016-fam-member.c
Normal file
11
test/err/bug2016-fam-member.c
Normal 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;
|
||||
};
|
9
test/err/bug2017-fam-element.c
Normal file
9
test/err/bug2017-fam-element.c
Normal 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 */
|
6
test/err/bug2020-definition.c
Normal file
6
test/err/bug2020-definition.c
Normal 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
13
test/err/bug2144.c
Normal 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);
|
||||
}
|
8
test/err/bug2162-none-extern-auto.c
Normal file
8
test/err/bug2162-none-extern-auto.c
Normal file
|
@ -0,0 +1,8 @@
|
|||
/* Bug #2162 - conflicting declarations in functions */
|
||||
|
||||
int main(void)
|
||||
{
|
||||
extern int i;
|
||||
int i = 42; /* Error */
|
||||
return i;
|
||||
}
|
8
test/err/bug2162-none-static-extern.c
Normal file
8
test/err/bug2162-none-static-extern.c
Normal file
|
@ -0,0 +1,8 @@
|
|||
/* Bug #2162 - conflicting declarations in functions */
|
||||
|
||||
int main(void)
|
||||
{
|
||||
static int i = 42;
|
||||
extern int i; /* Error */
|
||||
return i;
|
||||
}
|
10
test/err/bug2162-static-extern-auto.c
Normal file
10
test/err/bug2162-static-extern-auto.c
Normal 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;
|
||||
}
|
10
test/err/bug2162-static-static-extern.c
Normal file
10
test/err/bug2162-static-static-extern.c
Normal 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;
|
||||
}
|
|
@ -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
16
test/val/bug2020-ok.c
Normal 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
47
test/val/bug2135.c
Normal 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;
|
||||
}
|
|
@ -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) {
|
34
test/val/lib_common_htonl.c
Normal file
34
test/val/lib_common_htonl.c
Normal 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;
|
||||
}
|
34
test/val/lib_common_htons.c
Normal file
34
test/val/lib_common_htons.c
Normal 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user