diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..1a6397284 --- /dev/null +++ b/.editorconfig @@ -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 diff --git a/Contributing.md b/Contributing.md index 3b355373c..25c6217aa 100644 --- a/Contributing.md +++ b/Contributing.md @@ -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:
     lda #RETURN_VALUE
-    ldx #0 ; return value is char
+    ldx #0 ; Promote char return value
 
or, if the value is 0, you can use:
diff --git a/README.md b/README.md
index e0e2c24e7..3e04158e1 100644
--- a/README.md
+++ b/README.md
@@ -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
diff --git a/cfg/apple2-hgr.cfg b/cfg/apple2-hgr.cfg
index cfe577e00..109fbe4f6 100644
--- a/cfg/apple2-hgr.cfg
+++ b/cfg/apple2-hgr.cfg
@@ -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;
diff --git a/cfg/apple2-overlay.cfg b/cfg/apple2-overlay.cfg
index a0b7678c1..754ece90f 100644
--- a/cfg/apple2-overlay.cfg
+++ b/cfg/apple2-overlay.cfg
@@ -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;
diff --git a/cfg/apple2-system.cfg b/cfg/apple2-system.cfg
index 0170feb93..3dd94d793 100644
--- a/cfg/apple2-system.cfg
+++ b/cfg/apple2-system.cfg
@@ -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;
diff --git a/cfg/apple2.cfg b/cfg/apple2.cfg
index a6809cf89..19932b1f9 100644
--- a/cfg/apple2.cfg
+++ b/cfg/apple2.cfg
@@ -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;
diff --git a/cfg/apple2enh-hgr.cfg b/cfg/apple2enh-hgr.cfg
index cfe577e00..109fbe4f6 100644
--- a/cfg/apple2enh-hgr.cfg
+++ b/cfg/apple2enh-hgr.cfg
@@ -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;
diff --git a/cfg/apple2enh-overlay.cfg b/cfg/apple2enh-overlay.cfg
index a0b7678c1..754ece90f 100644
--- a/cfg/apple2enh-overlay.cfg
+++ b/cfg/apple2enh-overlay.cfg
@@ -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;
diff --git a/cfg/apple2enh-system.cfg b/cfg/apple2enh-system.cfg
index 0170feb93..3dd94d793 100644
--- a/cfg/apple2enh-system.cfg
+++ b/cfg/apple2enh-system.cfg
@@ -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;
diff --git a/cfg/apple2enh.cfg b/cfg/apple2enh.cfg
index a6809cf89..19932b1f9 100644
--- a/cfg/apple2enh.cfg
+++ b/cfg/apple2enh.cfg
@@ -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;
diff --git a/cfg/atari-overlay.cfg b/cfg/atari-overlay.cfg
index 9311a1b22..60f98e453 100644
--- a/cfg/atari-overlay.cfg
+++ b/cfg/atari-overlay.cfg
@@ -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;
diff --git a/cfg/atari-xex.cfg b/cfg/atari-xex.cfg
index cabde3708..deab5c7a5 100644
--- a/cfg/atari-xex.cfg
+++ b/cfg/atari-xex.cfg
@@ -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 {
diff --git a/cfg/atari.cfg b/cfg/atari.cfg
index 106c75e63..37337ea53 100644
--- a/cfg/atari.cfg
+++ b/cfg/atari.cfg
@@ -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;
 }
diff --git a/cfg/atarixl-largehimem.cfg b/cfg/atarixl-largehimem.cfg
index 38fb68db9..8f70597aa 100644
--- a/cfg/atarixl-largehimem.cfg
+++ b/cfg/atarixl-largehimem.cfg
@@ -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;
 }
diff --git a/cfg/atarixl-overlay.cfg b/cfg/atarixl-overlay.cfg
index 339228ea0..3b8da4256 100644
--- a/cfg/atarixl-overlay.cfg
+++ b/cfg/atarixl-overlay.cfg
@@ -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;
 
diff --git a/cfg/atarixl-xex.cfg b/cfg/atarixl-xex.cfg
index 1b76855d0..853096c6f 100644
--- a/cfg/atarixl-xex.cfg
+++ b/cfg/atarixl-xex.cfg
@@ -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;
diff --git a/cfg/atarixl.cfg b/cfg/atarixl.cfg
index cece23555..1517afb5a 100644
--- a/cfg/atarixl.cfg
+++ b/cfg/atarixl.cfg
@@ -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;
 }
diff --git a/cfg/atmos.cfg b/cfg/atmos.cfg
index 35f184f4f..4c370903a 100644
--- a/cfg/atmos.cfg
+++ b/cfg/atmos.cfg
@@ -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;
diff --git a/cfg/c64-overlay.cfg b/cfg/c64-overlay.cfg
index 0f42434ad..ae760b30c 100644
--- a/cfg/c64-overlay.cfg
+++ b/cfg/c64-overlay.cfg
@@ -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;
diff --git a/cfg/c64.cfg b/cfg/c64.cfg
index 5bd8d8240..59cadd46b 100644
--- a/cfg/c64.cfg
+++ b/cfg/c64.cfg
@@ -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;
 }
diff --git a/cfg/creativision.cfg b/cfg/creativision.cfg
index 2eb9ac427..f3b7ac0f4 100644
--- a/cfg/creativision.cfg
+++ b/cfg/creativision.cfg
@@ -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;
diff --git a/cfg/cx16-bank.cfg b/cfg/cx16-bank.cfg
index d3c2c02ae..264b6fcba 100644
--- a/cfg/cx16-bank.cfg
+++ b/cfg/cx16-bank.cfg
@@ -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;
diff --git a/cfg/cx16.cfg b/cfg/cx16.cfg
index 4b6025fb6..a160a6718 100644
--- a/cfg/cx16.cfg
+++ b/cfg/cx16.cfg
@@ -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;
 }
diff --git a/cfg/telestrat.cfg b/cfg/telestrat.cfg
index bd720fb8d..52b982eef 100644
--- a/cfg/telestrat.cfg
+++ b/cfg/telestrat.cfg
@@ -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;
diff --git a/doc/apple2.sgml b/doc/apple2.sgml
index 63b40c6f8..063cfc71f 100644
--- a/doc/apple2.sgml
+++ b/doc/apple2.sgml
@@ -427,8 +427,12 @@ The names in the parentheses denote the symbols to be used for static linking of
 
 
   
-  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 
+  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 

@@ -603,7 +626,7 @@ url="ca65.html" name="assembler manual">. The header file Example diff --git a/doc/apple2enh.sgml b/doc/apple2enh.sgml index 15ceed04f..30088521a 100644 --- a/doc/apple2enh.sgml +++ b/doc/apple2enh.sgml @@ -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 . 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 - 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 + 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

diff --git a/doc/ca65.sgml b/doc/ca65.sgml index 982c68949..b0ccf6f5e 100644 --- a/doc/ca65.sgml +++ b/doc/ca65.sgml @@ -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:

@@ -1714,7 +1714,7 @@ bloated code and a slowdown. Inline assembler

-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 @@ -1729,7 +1729,7 @@ or The first form is in the user namespace; and, is disabled by if the argument is not Note: Do not embed the assembler labels that are used as names of global -variables or functions into your int foo; diff --git a/doc/funcref.sgml b/doc/funcref.sgml index 2a6d77adc..524818b19 100644 --- a/doc/funcref.sgml +++ b/doc/funcref.sgml @@ -334,9 +334,11 @@ function. - + + + @@ -440,6 +442,16 @@ see also testcode/lib/em-test.c and samples/multidemo.c. . +

+ + + + + + + + +

@@ -452,6 +464,18 @@ see also testcode/lib/em-test.c and samples/multidemo.c. +

+ + + + + + + + +(incomplete) + +

@@ -1735,7 +1759,7 @@ used in presence of a prototype. , , -, + @@ -1880,7 +1904,7 @@ be used in presence of a prototype. , , , -, + @@ -1953,7 +1977,7 @@ sent a command to TALK and a secondary address if it needs one. , + @@ -2355,8 +2379,8 @@ function, in order to provide input from the keyboard. , , -, - + + @@ -3274,7 +3298,7 @@ used in presence of a prototype. , -, + @@ -3314,7 +3338,7 @@ used in presence of a prototype. , -, + @@ -3440,11 +3464,11 @@ int main(void) / +/, / -The function is specific to the Sym-1. +The function is specific to the Sym-1 and KIM-1. The return value is status. Non-zero status indicates an error. 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. , , -, + @@ -3833,7 +3857,7 @@ switching the CPU into double clock mode. , , -, + @@ -3949,7 +3973,8 @@ be used in presence of a prototype. , -, / +, , +/ +htonl

+ + + +/ + +The function is only available as fastcall function, so it may only +be used in presence of a prototype. + + + + + + +htons

+ + + +/ + +The function is only available as fastcall function, so it may only +be used in presence of a prototype. + + + + + isalnum

@@ -5084,11 +5148,11 @@ used in presence of a prototype. / +/, / -The function is specific to the Sym-1. +The function is specific to the Sym-1 and KIM-1. The return value is status. Non-zero status indicates an error. 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. , , -, + @@ -5757,6 +5821,44 @@ memory allocated for the driver. +ntohl

+ + + +/ + +The function is only available as fastcall function, so it may only +be used in presence of a prototype. + + + + + +ntohs

+ + + +/ + +The function is only available as fastcall function, so it may only +be used in presence of a prototype. + + + + + offsetof

@@ -6606,7 +6708,8 @@ be used in presence of a prototype. / 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. diff --git a/include/apple2.h b/include/apple2.h index 9f644bc97..8b9a3e0ea 100644 --- a/include/apple2.h +++ b/include/apple2.h @@ -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 diff --git a/include/apple2enh.h b/include/apple2enh.h index bfe5cdb18..3989d0b8d 100644 --- a/include/apple2enh.h +++ b/include/apple2enh.h @@ -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[]; diff --git a/include/arpa/inet.h b/include/arpa/inet.h new file mode 100644 index 000000000..cd353a2bb --- /dev/null +++ b/include/arpa/inet.h @@ -0,0 +1,67 @@ +/*****************************************************************************/ +/* */ +/* arpa/inet.h */ +/* */ +/* Endianness utilities for cc65 */ +/* */ +/* */ +/* */ +/* (C) 2023 Colin Leroy-Mira, */ +/* */ +/* */ +/* 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 diff --git a/include/cx16.h b/include/cx16.h index 66f21843e..5bbd21247 100644 --- a/include/cx16.h +++ b/include/cx16.h @@ -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 */ diff --git a/libsrc/Makefile b/libsrc/Makefile index d8671d2da..78e362573 100644 --- a/libsrc/Makefile +++ b/libsrc/Makefile @@ -131,8 +131,8 @@ $(TARGETS): | ../lib else # TARGET -CA65FLAGS = -CC65FLAGS = -Or -W error +CA65FLAGS = -g +CC65FLAGS = -g -Or -W error EXTZP = cbm510 \ cbm610 \ diff --git a/libsrc/apple2/cputc.s b/libsrc/apple2/cputc.s index 30383fcfe..035b1c047 100644 --- a/libsrc/apple2/cputc.s +++ b/libsrc/apple2/cputc.s @@ -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 diff --git a/libsrc/apple2/exec.s b/libsrc/apple2/exec.s index d5cbf8788..27a6487bd 100644 --- a/libsrc/apple2/exec.s +++ b/libsrc/apple2/exec.s @@ -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 diff --git a/libsrc/apple2/ser/a2.gs.s b/libsrc/apple2/ser/a2.gs.s new file mode 100644 index 000000000..7f6bc824d --- /dev/null +++ b/libsrc/apple2/ser/a2.gs.s @@ -0,0 +1,713 @@ +; +; Serial driver for the Apple IIgs Zilog Z8530. +; +; Colin Leroy-Mira , 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 diff --git a/libsrc/apple2/ser/a2.ssc.s b/libsrc/apple2/ser/a2.ssc.s index 6ad9c3825..022ef2fd5 100644 --- a/libsrc/apple2/ser/a2.ssc.s +++ b/libsrc/apple2/ser/a2.ssc.s @@ -26,6 +26,7 @@ .include "ser-error.inc" .macpack module + .macpack cpu ; ------------------------------------------------------------------------ ; Header. Includes jump table @@ -37,8 +38,8 @@ .endif ; Driver signature - .byte $73, $65, $72 ; "ser" - .byte SER_API_VERSION ; Serial API version number + .byte $73, $65, $72 ; "ser" + .byte SER_API_VERSION ; Serial API version number ; Library reference .addr $0000 @@ -57,13 +58,17 @@ ;---------------------------------------------------------------------------- ; I/O definitions +.if (.cpu .bitand CPU_ISET_65C02) +ACIA := $C088 +.else Offset = $8F ; Move 6502 false read out of I/O to page $BF +ACIA := $C088-Offset +.endif -ACIA = $C088-Offset -ACIA_DATA = ACIA+0 ; Data register -ACIA_STATUS = ACIA+1 ; Status register -ACIA_CMD = ACIA+2 ; Command register -ACIA_CTRL = ACIA+3 ; Control register +ACIA_DATA := ACIA+0 ; Data register +ACIA_STATUS := ACIA+1 ; Status register +ACIA_CMD := ACIA+2 ; Command register +ACIA_CTRL := ACIA+3 ; Control register ;---------------------------------------------------------------------------- ; Global variables @@ -72,16 +77,17 @@ ACIA_CTRL = ACIA+3 ; Control register RecvHead: .res 1 ; Head of receive buffer RecvTail: .res 1 ; Tail of receive buffer -RecvFreeCnt: .res 1 ; Number of bytes in receive buffer +RecvFreeCnt: .res 1 ; Number of free bytes in receive buffer SendHead: .res 1 ; Head of send buffer SendTail: .res 1 ; Tail of send buffer -SendFreeCnt: .res 1 ; Number of bytes in send buffer +SendFreeCnt: .res 1 ; Number of free bytes in send buffer Stopped: .res 1 ; Flow-stopped flag -RtsOff: .res 1 ; +RtsOff: .res 1 ; Cached value of command register with + ; flow stopped -RecvBuf: .res 256 ; Receive buffers: 256 bytes -SendBuf: .res 256 ; Send buffers: 256 bytes +RecvBuf: .res 256 ; Receive buffer: 256 bytes +SendBuf: .res 256 ; Send buffer: 256 bytes Index: .res 1 ; I/O register index @@ -91,8 +97,9 @@ Slot: .byte $02 ; Default to SSC in slot 2 .rodata - ; Tables used to translate RS232 params into register values -BaudTable: ; bit7 = 1 means setting is invalid +BaudTable: ; Table used to translate RS232 baudrate param + ; into control register value + ; bit7 = 1 means setting is invalid .byte $FF ; SER_BAUD_45_5 .byte $01 ; SER_BAUD_50 .byte $02 ; SER_BAUD_75 @@ -113,30 +120,61 @@ BaudTable: ; bit7 = 1 means setting is invalid .byte $FF ; SER_BAUD_57600 .byte $FF ; SER_BAUD_115200 .byte $FF ; SER_BAUD_230400 -BitTable: + +BitTable: ; Table used to translate RS232 databits param + ; into control register value .byte $60 ; SER_BITS_5 .byte $40 ; SER_BITS_6 .byte $20 ; SER_BITS_7 .byte $00 ; SER_BITS_8 -StopTable: + +StopTable: ; Table used to translate RS232 stopbits param + ; into control register value .byte $00 ; SER_STOP_1 .byte $80 ; SER_STOP_2 -ParityTable: + +ParityTable: ; Table used to translate RS232 parity param + ; into command register value .byte $00 ; SER_PAR_NONE .byte $20 ; SER_PAR_ODD .byte $60 ; SER_PAR_EVEN .byte $A0 ; SER_PAR_MARK .byte $E0 ; SER_PAR_SPACE -IdOfsTable: + +IdOfsTable: ; Table of bytes positions, used to check five + ; specific bytes on the slot's firmware to make + ; sure this is an SSC (or Apple //c comm port) + ; firmware that drives an ACIA 6551 chip. + ; + ; The SSC firmware and the Apple //c(+) comm + ; port firmware all begin with a BIT instruction. + ; The IIgs, on the other hand, has a + ; Zilog Z8530 chip and its firmware starts with + ; a SEP instruction. We don't want to load this + ; driver on the IIgs' serial port. We'll + ; differentiate the firmware on this byte. + ; + ; The next four bytes we check are the Pascal + ; Firmware Protocol Bytes that identify a + ; serial card. Those are the same bytes for + ; SSC firmwares, Apple //c firmwares and IIgs + ; Zilog Z8530 firmwares - which is the reason + ; we have to check for the firmware's first + ; instruction too. + .byte $00 ; First instruction .byte $05 ; Pascal 1.0 ID byte .byte $07 ; Pascal 1.0 ID byte .byte $0B ; Pascal 1.1 generic signature byte .byte $0C ; Device signature byte -IdValTable: - .byte $38 ; Fixed - .byte $18 ; Fixed - .byte $01 ; Fixed - .byte $31 ; Serial or parallel I/O card type 1 + +IdValTable: ; Table of expected values for the five checked + ; bytes + .byte $2C ; BIT + .byte $38 ; ID Byte 0 (from Pascal 1.0), fixed + .byte $18 ; ID Byte 1 (from Pascal 1.0), fixed + .byte $01 ; Generic signature for Pascal 1.1, fixed + .byte $31 ; Device signature byte (serial or + ; parallel I/O card type 1) IdTableLen = * - IdValTable @@ -163,12 +201,10 @@ SER_CLOSE: ldx Index ; Check for open port beq :+ - ; Deactivate DTR and disable 6551 interrupts - lda #%00001010 + lda #%00001010 ; Deactivate DTR and disable 6551 interrupts sta ACIA_CMD,x - ; Done, return an error code -: lda #SER_ERR_OK +: lda #SER_ERR_OK ; Done, return an error code .assert SER_ERR_OK = 0, error tax stx Index ; Mark port as closed @@ -185,96 +221,96 @@ SER_OPEN: ora Slot sta ptr2+1 - ; Check Pascal 1.1 Firmware Protocol ID bytes -: ldy IdOfsTable,x +: ldy IdOfsTable,x ; Check Pascal 1.1 Firmware Protocol ID bytes lda IdValTable,x cmp (ptr2),y - bne NoDevice + bne NoDev inx cpx #IdTableLen bcc :- - ; Convert slot to I/O register index - lda Slot + lda Slot ; Convert slot to I/O register index asl asl asl asl - adc #Offset ; Assume carry to be clear +.if .not (.cpu .bitand CPU_ISET_65C02) + adc #Offset ; Assume carry to be clear +.endif tax ; Check if the handshake setting is valid - ldy #SER_PARAMS::HANDSHAKE ; Handshake + ldy #SER_PARAMS::HANDSHAKE lda (ptr1),y - cmp #SER_HS_HW ; This is all we support - bne InvParam + cmp #SER_HS_HW ; This is all we support + bne InvParm - ; Initialize buffers - ldy #$00 + ldy #$00 ; Initialize buffers sty Stopped sty RecvHead sty RecvTail sty SendHead sty SendTail - dey ; Y = 255 + dey ; Y = 255 sty RecvFreeCnt sty SendFreeCnt ; Set the value for the control register, which contains stop bits, ; word length and the baud rate. ldy #SER_PARAMS::BAUDRATE - lda (ptr1),y ; Baudrate index + lda (ptr1),y ; Baudrate index tay - lda BaudTable,y ; Get 6551 value - bmi InvBaud ; Branch if rate not supported + lda BaudTable,y ; Get 6551 value + bmi InvBaud ; Branch if rate not supported sta tmp1 - ldy #SER_PARAMS::DATABITS ; Databits - lda (ptr1),y + ldy #SER_PARAMS::DATABITS + lda (ptr1),y ; Databits index tay - lda BitTable,y + lda BitTable,y ; Get 6551 value ora tmp1 sta tmp1 - ldy #SER_PARAMS::STOPBITS ; Stopbits - lda (ptr1),y + ldy #SER_PARAMS::STOPBITS + lda (ptr1),y ; Stopbits index tay - lda StopTable,y + lda StopTable,y ; Get 6551 value ora tmp1 - ora #%00010000 ; Receiver clock source = baudrate + ora #%00010000 ; Set receiver clock source = baudrate sta ACIA_CTRL,x ; Set the value for the command register. We remember the base value ; in RtsOff, since we will have to manipulate ACIA_CMD often. - ldy #SER_PARAMS::PARITY ; Parity - lda (ptr1),y + ldy #SER_PARAMS::PARITY + lda (ptr1),y ; Parity index tay - lda ParityTable,y - ora #%00000001 ; DTR active - sta RtsOff - ora #%00001000 ; Enable receive interrupts + lda ParityTable,y ; Get 6551 value + + ora #%00000001 ; Set DTR active + sta RtsOff ; Store value to easily handle flow control later + ora #%00001000 ; Enable receive interrupts (RTS low) sta ACIA_CMD,x ; Done - stx Index ; Mark port as open + stx Index ; Mark port as open lda #SER_ERR_OK .assert SER_ERR_OK = 0, error tax rts ; Device (hardware) not found -NoDevice:lda #SER_ERR_NO_DEVICE - ldx #0 ; return value is char +NoDev: lda #SER_ERR_NO_DEVICE + ldx #$00 ; Promote char return value rts ; Invalid parameter -InvParam:lda #SER_ERR_INIT_FAILED - ldx #0 ; return value is char +InvParm:lda #SER_ERR_INIT_FAILED + ldx #$00 ; Promote char return value rts ; Baud rate not available InvBaud:lda #SER_ERR_BAUD_UNAVAIL - ldx #0 ; return value is char + ldx #$00 ; Promote char return value rts ;---------------------------------------------------------------------------- @@ -284,38 +320,38 @@ InvBaud:lda #SER_ERR_BAUD_UNAVAIL SER_GET: ldx Index - ldy SendFreeCnt ; Send data if necessary - iny ; Y == $FF? - beq :+ - lda #$00 ; TryHard = false - jsr TryToSend - ; Check for buffer empty -: lda RecvFreeCnt ; (25) + lda RecvFreeCnt ; Check for buffer empty cmp #$FF bne :+ lda #SER_ERR_NO_DATA - ldx #0 ; return value is char + ldx #$00 ; Promote char return value rts - ; Check for flow stopped & enough free: release flow control -: ldy Stopped ; (34) +: ldy Stopped ; Check for flow stopped beq :+ - cmp #63 + cmp #63 ; Enough free? bcc :+ +.if (.cpu .bitand CPU_ISET_65C02) + stz Stopped ; Release flow control +.else lda #$00 sta Stopped +.endif lda RtsOff ora #%00001000 sta ACIA_CMD,x - ; Get byte from buffer -: ldy RecvHead ; (41) +: ldy RecvHead ; Get byte from buffer lda RecvBuf,y inc RecvHead inc RecvFreeCnt - ldx #$00 ; (59) + ldx #$00 +.if (.cpu .bitand CPU_ISET_65C02) + sta (ptr1) ; Store it for caller +.else sta (ptr1,x) +.endif txa ; Return code = 0 rts @@ -326,28 +362,26 @@ SER_GET: SER_PUT: ldx Index - ; Try to send - ldy SendFreeCnt - iny ; Y = $FF? + ldy SendFreeCnt ; Anything to send first? + cpy #$FF ; No beq :+ pha lda #$00 ; TryHard = false - jsr TryToSend + jsr TryToSend ; Try to flush send buffer pla - ; Put byte into send buffer & send -: ldy SendFreeCnt + ldy SendFreeCnt ; Reload SendFreeCnt after TryToSend bne :+ lda #SER_ERR_OVERFLOW - ldx #0 ; return value is char + ldx #$00 ; Promote char return value rts -: ldy SendTail +: ldy SendTail ; Put byte into send buffer sta SendBuf,y inc SendTail dec SendFreeCnt lda #$FF ; TryHard = true - jsr TryToSend + jsr TryToSend ; Flush send buffer lda #SER_ERR_OK .assert SER_ERR_OK = 0, error tax @@ -369,26 +403,25 @@ SER_STATUS: ;---------------------------------------------------------------------------- ; SER_IOCTL: Driver defined entry point. The wrapper will pass a pointer to ioctl ; specific data in ptr1, and the ioctl code in A. +; The ioctl data is the slot number to open. ; Must return an SER_ERR_xx code in a/x. SER_IOCTL: - ; Check data msb and code to be 0 - ora ptr1+1 + ora ptr1+1 ; Check data msb and code to be 0 bne :+ - ; Check data lsb to be [1..7] - ldx ptr1 + ldx ptr1 ; Check data lsb to be [1..7] beq :+ cpx #7+1 bcs :+ - stx Slot + stx Slot ; Store slot .assert SER_ERR_OK = 0, error tax rts : lda #SER_ERR_INV_IOCTL - ldx #0 ; return value is char + ldx #$00 ; Promote char return value rts ;---------------------------------------------------------------------------- @@ -404,19 +437,18 @@ SER_IRQ: and #$08 beq Done ; Jump if no ACIA interrupt lda ACIA_DATA,x ; Get byte from ACIA - ldy RecvFreeCnt ; Check if we have free space left + ldx RecvFreeCnt ; Check if we have free space left beq Flow ; Jump if no space in receive buffer ldy RecvTail ; Load buffer pointer sta RecvBuf,y ; Store received byte in buffer inc RecvTail ; Increment buffer pointer dec RecvFreeCnt ; Decrement free space counter - ldy RecvFreeCnt ; Check for buffer space low - cpy #33 + cpx #33 ; Check for buffer space low bcc Flow ; Assert flow control if buffer space low rts ; Interrupt handled (carry already set) - ; Assert flow control if buffer space too low -Flow: lda RtsOff +Flow: ldx Index ; Assert flow control if buffer space too low +lda RtsOff sta ACIA_CMD,x sta Stopped sec ; Interrupt handled @@ -427,26 +459,24 @@ Done: rts TryToSend: sta tmp1 ; Remember tryHard flag -Again: lda SendFreeCnt - cmp #$FF - beq Quit ; Bail out +NextByte: + lda SendFreeCnt ; Is there anything to send? This can happen if + cmp #$FF ; we got interrupted by RX while sending, and + beq Quit ; flow control was asserted. - ; Check for flow stopped - lda Stopped - bne Quit ; Bail out +Again: lda Stopped ; Is flow stopped? + bne Quit ; Yes, Bail out - ; Check that ACIA is ready to send - lda ACIA_STATUS,x + lda ACIA_STATUS,x ; Check that ACIA is ready to send and #$10 - bne Send + bne Send ; It is! bit tmp1 ; Keep trying if must try hard bmi Again Quit: rts - ; Send byte and try again -Send: ldy SendHead +Send: ldy SendHead ; Get first byte to send lda SendBuf,y - sta ACIA_DATA,x + sta ACIA_DATA,x ; Send it inc SendHead inc SendFreeCnt - jmp Again + jmp NextByte ; And try next one diff --git a/libsrc/atmos/ser/atmos-acia.s b/libsrc/atmos/ser/atmos-acia.s index f679125d1..1509803d2 100644 --- a/libsrc/atmos/ser/atmos-acia.s +++ b/libsrc/atmos/ser/atmos-acia.s @@ -227,14 +227,8 @@ InvBaud:lda #, 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 diff --git a/libsrc/common/ntohs.s b/libsrc/common/ntohs.s new file mode 100644 index 000000000..042ddb005 --- /dev/null +++ b/libsrc/common/ntohs.s @@ -0,0 +1,16 @@ +; +; Colin Leroy-Mira , 2023-09-06 +; +; int __fastcall__ ntohs (int val); +; + +.export _ntohs, _htons +.importzp tmp1 + +_htons := _ntohs + +_ntohs: + sta tmp1 + txa + ldx tmp1 + rts diff --git a/libsrc/conio/cputs.s b/libsrc/conio/cputs.s index 41191a0b0..62e757b84 100644 --- a/libsrc/conio/cputs.s +++ b/libsrc/conio/cputs.s @@ -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 - - diff --git a/libsrc/conio/vcprintf.s b/libsrc/conio/vcprintf.s index 084efe089..595a2d2c5 100644 --- a/libsrc/conio/vcprintf.s +++ b/libsrc/conio/vcprintf.s @@ -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 ; diff --git a/libsrc/creativision/cputc.s b/libsrc/creativision/cputc.s index 437b738b2..4389234c1 100644 --- a/libsrc/creativision/cputc.s +++ b/libsrc/creativision/cputc.s @@ -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 diff --git a/libsrc/kim1/scandisplay.s b/libsrc/kim1/scandisplay.s index 0f46a5de4..768adb2b9 100644 --- a/libsrc/kim1/scandisplay.s +++ b/libsrc/kim1/scandisplay.s @@ -15,7 +15,6 @@ sta $FA ; Middle display data jsr popa sta $FB ; Leftmost display data - jsr SCANDS - rts + jmp SCANDS .endproc diff --git a/libsrc/lynx/extzp.inc b/libsrc/lynx/extzp.inc index 2b0f68701..7103ff5b6 100644 --- a/libsrc/lynx/extzp.inc +++ b/libsrc/lynx/extzp.inc @@ -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 - - - diff --git a/libsrc/lynx/extzp.s b/libsrc/lynx/extzp.s index f22cfaefb..df53c3d9a 100644 --- a/libsrc/lynx/extzp.s +++ b/libsrc/lynx/extzp.s @@ -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 - diff --git a/libsrc/plus4/ser/plus4-stdser.s b/libsrc/plus4/ser/plus4-stdser.s index fbdc61b2e..77445c7a2 100644 --- a/libsrc/plus4/ser/plus4-stdser.s +++ b/libsrc/plus4/ser/plus4-stdser.s @@ -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 diff --git a/libsrc/serial/ser-kernel.s b/libsrc/serial/ser-kernel.s index b6c57a3b5..1514bcf77 100644 --- a/libsrc/serial/ser-kernel.s +++ b/libsrc/serial/ser-kernel.s @@ -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 diff --git a/src/ca65/instr.c b/src/ca65/instr.c index 89162c3c6..da6bd6e44 100644 --- a/src/ca65/instr.c +++ b/src/ca65/instr.c @@ -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 */ diff --git a/src/cc65.props b/src/cc65.props index ef5a37fea..19fb0b646 100644 --- a/src/cc65.props +++ b/src/cc65.props @@ -21,6 +21,7 @@ true _CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;_WIN32_WINNT=0x0601;WINVER=0x0601;NTDDI_VERSION=0x06010000;%(PreprocessorDefinitions) common + /utf-8 %(AdditionalOptions) $(IntDir)..\..\common\$(Configuration)\common.lib @@ -42,13 +43,13 @@ false - true MultiThreaded true MaxSpeed + true false false @@ -57,6 +58,7 @@ true true UseLinkTimeCodeGeneration + /EMITTOOLVERSIONINFO:NO /NOVCFEATURE /NOCOFFGRPINFO %(AdditionalOptions) diff --git a/src/cc65.vcxproj b/src/cc65.vcxproj index 7e2e8ea8c..556c616b0 100644 --- a/src/cc65.vcxproj +++ b/src/cc65.vcxproj @@ -110,6 +110,7 @@ + @@ -190,6 +191,7 @@ + diff --git a/src/cc65/compile.c b/src/cc65/compile.c index 73380f3df..7bf3cd8ab 100644 --- a/src/cc65/compile.c +++ b/src/cc65/compile.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,17 +326,24 @@ static void Parse (void) if (Sym && IsTypeFunc (Sym->Type)) { /* Function */ - if (!comma) { - if (CurTok.Tok == TOK_SEMI) { - /* Prototype only */ - NextToken (); - } else { - /* Parse the function body */ - NewFunc (Sym, FuncDef); - - /* Make sure we aren't omitting any work */ - CheckDeferredOpAllDone (); + if (CurTok.Tok == TOK_SEMI) { + /* Prototype only */ + NextToken (); + } else if (CurTok.Tok == TOK_LCURLY) { + /* ISO C: The type category in a function definition cannot be + ** inherited from a typedef. + */ + if (IsTypeFunc (Spec.Type) && TypeCmp (Sym->Type, Spec.Type).C >= TC_EQUAL) { + Error ("Function cannot be defined with a typedef"); + } else if (comma) { + Error ("';' expected after top level declarator"); } + + /* Parse the function body anyways */ + NewFunc (Sym, FuncDef); + + /* Make sure we aren't omitting any work */ + CheckDeferredOpAllDone (); } } else { diff --git a/src/cc65/declare.c b/src/cc65/declare.c index 59eb555c4..eab0ff0d6 100644 --- a/src/cc65/declare.c +++ b/src/cc65/declare.c @@ -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'; } diff --git a/src/cc65/declare.h b/src/cc65/declare.h index ee9e1fc63..0facccba3 100644 --- a/src/cc65/declare.h +++ b/src/cc65/declare.h @@ -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) diff --git a/src/cc65/expr.c b/src/cc65/expr.c index 6a101bf5f..6e71f9eb0 100644 --- a/src/cc65/expr.c +++ b/src/cc65/expr.c @@ -31,6 +31,7 @@ #include "macrotab.h" #include "preproc.h" #include "scanner.h" +#include "seqpoint.h" #include "shiftexpr.h" #include "stackptr.h" #include "standard.h" @@ -691,6 +692,7 @@ void DoDeferred (unsigned Flags, ExprDesc* Expr) int I; unsigned Size = 0; int Count = GetDeferredOpCount (); + unsigned StmtFlags = GetSQPFlags (); /* Nothing to be done */ if (Count <= 0) { @@ -698,26 +700,38 @@ void DoDeferred (unsigned Flags, ExprDesc* Expr) } /* Backup some regs/processor flags around the inc/dec */ - if ((Flags & SQP_KEEP_TEST) != 0 && ED_NeedsTest (Expr)) { + if ((StmtFlags & SQP_KEEP_TEST) != 0 || + ((Flags & SQP_KEEP_TEST) != 0 && ED_NeedsTest (Expr))) { /* Sufficient to add a pair of PHP/PLP for all cases */ AddCodeLine ("php"); } - /* Backup the content of EAX around the inc/dec */ - if ((Flags & SQP_KEEP_EAX) != 0 && ED_NeedsPrimary (Expr)) { - /* Get the size */ - Size = CheckedSizeOf (Expr->Type); + if ((Flags & SQP_MASK_EAX) != 0 && ED_NeedsPrimary (Expr)) { + Size = SizeOf (Expr->Type); + } - if (Size < 2) { - AddCodeLine ("pha"); - } else if (Size < 3) { - AddCodeLine ("sta regsave"); - AddCodeLine ("stx regsave+1"); - } else { - AddCodeLine ("jsr saveeax"); + /* Get the size of the backup */ + if ((StmtFlags & SQP_MASK_EAX) != 0) { + switch (StmtFlags & SQP_MASK_EAX) { + case SQP_KEEP_A: if (Size < 1) Size = 1; break; + case SQP_KEEP_AX: if (Size < 2) Size = 2; break; + case SQP_KEEP_EAX: if (Size < 4) Size = 4; break; + default: ; } } + /* Backup the content of EAX around the inc/dec */ + if (Size == 1) { + AddCodeLine ("pha"); + } else if (Size == 2) { + AddCodeLine ("sta regsave"); + AddCodeLine ("stx regsave+1"); + } else if (Size == 3 || Size == 4) { + AddCodeLine("jsr saveeax"); + } else if (Size > 4) { + Error ("Unsupported deferred operand size: %u", Size); + } + for (I = 0; I < Count; ++I) { DeferredOp* Op = CollAtUnchecked (&DeferredOps, I); switch (Op->OpType) { @@ -735,19 +749,18 @@ void DoDeferred (unsigned Flags, ExprDesc* Expr) CollDeleteAll (&DeferredOps); /* Restore the content of EAX around the inc/dec */ - if ((Flags & SQP_KEEP_EAX) != 0 && ED_NeedsPrimary (Expr)) { - if (Size < 2) { - AddCodeLine ("pla"); - } else if (Size < 3) { - AddCodeLine ("lda regsave"); - AddCodeLine ("ldx regsave+1"); - } else { - AddCodeLine ("jsr resteax"); - } + if (Size == 1) { + AddCodeLine ("pla"); + } else if (Size == 2) { + AddCodeLine ("lda regsave"); + AddCodeLine ("ldx regsave+1"); + } else if (Size == 3 || Size == 4) { + AddCodeLine ("jsr resteax"); } /* Restore the regs/processor flags around the inc/dec */ - if ((Flags & SQP_KEEP_TEST) != 0 && ED_NeedsTest (Expr)) { + if ((StmtFlags & SQP_KEEP_TEST) != 0 || + ((Flags & SQP_KEEP_TEST) != 0 && ED_NeedsTest (Expr))) { /* Sufficient to pop the processor flags */ AddCodeLine ("plp"); } @@ -1049,6 +1062,10 @@ static void FunctionCall (ExprDesc* Expr) /* Parse the argument list and pass them to the called function */ ArgSize = FunctionArgList (Func, IsFastcall, Expr); + if (ArgSize > 0xFF && (Func->Flags & FD_VARIADIC) != 0) { + Error ("Total size of all arguments passed to a variadic function cannot exceed 255 bytes"); + } + /* We need the closing paren here */ ConsumeRParen (); @@ -1372,6 +1389,7 @@ static void Primary (ExprDesc* E) case TOK_A: /* Register pseudo variable */ + SetSQPFlags (SQP_KEEP_A); E->Type = type_uchar; E->Flags = E_LOC_PRIMARY | E_RTYPE_LVAL; NextToken (); @@ -1379,6 +1397,7 @@ static void Primary (ExprDesc* E) case TOK_AX: /* Register pseudo variable */ + SetSQPFlags (SQP_KEEP_AX); E->Type = type_uint; E->Flags = E_LOC_PRIMARY | E_RTYPE_LVAL; NextToken (); @@ -1386,6 +1405,7 @@ static void Primary (ExprDesc* E) case TOK_EAX: /* Register pseudo variable */ + SetSQPFlags (SQP_KEEP_EAX); E->Type = type_ulong; E->Flags = E_LOC_PRIMARY | E_RTYPE_LVAL; NextToken (); @@ -1453,7 +1473,7 @@ static void StructRef (ExprDesc* Expr) /* Skip the token and check for an identifier */ NextToken (); if (CurTok.Tok != TOK_IDENT) { - Error ("Identifier expected"); + Error ("Identifier expected for %s member", GetBasicTypeName (Expr->Type)); /* Make the expression an integer at address zero */ ED_MakeConstAbs (Expr, 0, type_int); return; diff --git a/src/cc65/expr.h b/src/cc65/expr.h index 5644fb82d..8bf7c00b5 100644 --- a/src/cc65/expr.h +++ b/src/cc65/expr.h @@ -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 */ diff --git a/src/cc65/goto.c b/src/cc65/goto.c index 7d3ff1a6a..44ae0595e 100644 --- a/src/cc65/goto.c +++ b/src/cc65/goto.c @@ -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" diff --git a/src/cc65/initdata.c b/src/cc65/initdata.c index 39c1655f0..75c913b60 100644 --- a/src/cc65/initdata.c +++ b/src/cc65/initdata.c @@ -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 */ diff --git a/src/cc65/locals.c b/src/cc65/locals.c index 0d5b12925..e349f8031 100644 --- a/src/cc65/locals.c +++ b/src/cc65/locals.c @@ -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" diff --git a/src/cc65/seqpoint.c b/src/cc65/seqpoint.c new file mode 100644 index 000000000..a6d992113 --- /dev/null +++ b/src/cc65/seqpoint.c @@ -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; +} diff --git a/src/cc65/seqpoint.h b/src/cc65/seqpoint.h new file mode 100644 index 000000000..07ff0d315 --- /dev/null +++ b/src/cc65/seqpoint.h @@ -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 diff --git a/src/cc65/stdfunc.c b/src/cc65/stdfunc.c index d22c73dcf..e968aaf1f 100644 --- a/src/cc65/stdfunc.c +++ b/src/cc65/stdfunc.c @@ -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" diff --git a/src/cc65/stmt.c b/src/cc65/stmt.c index 7355e88a8..613129e1b 100644 --- a/src/cc65/stmt.c +++ b/src/cc65/stmt.c @@ -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; } diff --git a/src/cc65/symtab.c b/src/cc65/symtab.c index a2bbf13dd..951ed9e5e 100644 --- a/src/cc65/symtab.c +++ b/src/cc65/symtab.c @@ -1225,6 +1225,15 @@ SymEntry* AddLocalSym (const char* Name, const Type* T, unsigned Flags, int Offs /* Do we have an entry with this name already? */ SymEntry* Entry = FindSymInTable (Tab, Name, HashStr (Name)); if (Entry) { + int CheckExtern = 0; + if ((Flags & SC_STRUCTFIELD) == 0) { + while (Entry && (Entry->Flags & SC_ALIAS) == SC_ALIAS) { + /* Get the aliased entry */ + Entry = Entry->V.A.Field; + /* Check for conflict with local storage class */ + CheckExtern = 1; + } + } /* We have a symbol with this name already */ if (HandleSymRedefinition (Entry, T, Flags)) { @@ -1234,19 +1243,14 @@ SymEntry* AddLocalSym (const char* Name, const Type* T, unsigned Flags, int Offs if (SymIsDef (Entry) && (Flags & SC_DEF) == SC_DEF) { Error ("Multiple definition of '%s'", Entry->Name); Entry = 0; - } else if ((Flags & (SC_AUTO | SC_REGISTER)) != 0 && - (Entry->Flags & SC_EXTERN) != 0) { - /* Check for local storage class conflict */ - Error ("Declaration of '%s' with no linkage follows extern declaration", - Name); - Entry = 0; - } else { - /* If a static declaration follows a non-static declaration, - ** then it is an error. - */ - if ((Flags & SC_DEF) && - (Flags & SC_EXTERN) == 0 && - (Entry->Flags & SC_EXTERN) != 0) { + } else if (CheckExtern) { + if ((Flags & (SC_AUTO | SC_REGISTER)) != 0) { + Error ("Declaration of '%s' with no linkage follows extern declaration", Name); + Entry = 0; + } else if ((Flags & SC_DEF) != 0 && (Flags & SC_EXTERN) == 0) { + /* If a static declaration follows a non-static declaration, + ** then it is an error. + */ Error ("Static declaration of '%s' follows extern declaration", Name); Entry = 0; } @@ -1340,7 +1344,8 @@ SymEntry* AddGlobalSym (const char* Name, const Type* T, unsigned Flags) Name); Entry = 0; } else if ((Flags & SC_ESUTYPEMASK) != SC_TYPEDEF) { - /* If a static declaration follows a non-static declaration, then the result is undefined. + /* If a static declaration follows a non-static declaration, then + ** the result is undefined. ** Most compilers choose to either give an error at compile time, ** or remove the extern property for a link time error if used. */ @@ -1348,6 +1353,7 @@ SymEntry* AddGlobalSym (const char* Name, const Type* T, unsigned Flags) (Flags & SC_EXTERN) == 0 && (Entry->Flags & SC_EXTERN) != 0) { Error ("Static declaration of '%s' follows non-static declaration", Name); + Entry = 0; } else if ((Flags & SC_EXTERN) != 0 && (Entry->Owner == SymTab0 || (Entry->Flags & SC_DEF) != 0) && (Entry->Flags & SC_EXTERN) == 0) { @@ -1359,14 +1365,15 @@ SymEntry* AddGlobalSym (const char* Name, const Type* T, unsigned Flags) */ if (Entry->Owner == SymTab0) { if ((Flags & SC_STORAGE) == 0) { - /* Linkage must be unchanged. - ** The C standard specifies that a later extern declaration will be ignored, - ** and will use the previous linkage instead. Giving a warning for this case. + /* The C standard specifies that a later extern declaration will keep + ** the previously declared internal or external linkage unchanged. + ** Though not required by the standard, we are warning on this case. */ Flags &= ~SC_EXTERN; - Warning ("Extern declaration of '%s' follows static declaration, extern ignored", Name); + Warning ("Extern declaration of '%s' follows static declaration, linkage unchanged", Name); } else { Error ("Non-static declaration of '%s' follows static declaration", Name); + Entry = 0; } } else { Error ("Extern declaration of '%s' follows static declaration", Name); diff --git a/src/cc65/testexpr.c b/src/cc65/testexpr.c index bad8b95f1..14160f13f 100644 --- a/src/cc65/testexpr.c +++ b/src/cc65/testexpr.c @@ -39,6 +39,7 @@ #include "expr.h" #include "loadexpr.h" #include "scanner.h" +#include "seqpoint.h" #include "testexpr.h" diff --git a/src/msbuild.cmd b/src/msbuild.cmd index 2e1821f0a..092bfb578 100644 --- a/src/msbuild.cmd +++ b/src/msbuild.cmd @@ -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 %* diff --git a/test/asm/err/jmp-indirect-6502-error.s b/test/asm/err/jmp-indirect-6502-error.s new file mode 100644 index 000000000..aadc37b30 --- /dev/null +++ b/test/asm/err/jmp-indirect-6502-error.s @@ -0,0 +1,4 @@ +; test that jmp (indirect) on a page boundary will give an error for 6502 CPU + +.p02 +jmp ($10FF) diff --git a/test/asm/val/jmp-indirect-success.s b/test/asm/val/jmp-indirect-success.s new file mode 100644 index 000000000..592666576 --- /dev/null +++ b/test/asm/val/jmp-indirect-success.s @@ -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 diff --git a/test/err/bug2016-fam-member.c b/test/err/bug2016-fam-member.c new file mode 100644 index 000000000..02c9ec275 --- /dev/null +++ b/test/err/bug2016-fam-member.c @@ -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; +}; diff --git a/test/err/bug2017-fam-element.c b/test/err/bug2017-fam-element.c new file mode 100644 index 000000000..195ca6597 --- /dev/null +++ b/test/err/bug2017-fam-element.c @@ -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 */ diff --git a/test/err/bug2020-definition.c b/test/err/bug2020-definition.c new file mode 100644 index 000000000..7443e3a9a --- /dev/null +++ b/test/err/bug2020-definition.c @@ -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 */ diff --git a/test/err/bug2144.c b/test/err/bug2144.c new file mode 100644 index 000000000..eb27d672b --- /dev/null +++ b/test/err/bug2144.c @@ -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); +} diff --git a/test/err/bug2162-none-extern-auto.c b/test/err/bug2162-none-extern-auto.c new file mode 100644 index 000000000..777fc48e7 --- /dev/null +++ b/test/err/bug2162-none-extern-auto.c @@ -0,0 +1,8 @@ +/* Bug #2162 - conflicting declarations in functions */ + +int main(void) +{ + extern int i; + int i = 42; /* Error */ + return i; +} diff --git a/test/err/bug2162-none-static-extern.c b/test/err/bug2162-none-static-extern.c new file mode 100644 index 000000000..cffb6a3bf --- /dev/null +++ b/test/err/bug2162-none-static-extern.c @@ -0,0 +1,8 @@ +/* Bug #2162 - conflicting declarations in functions */ + +int main(void) +{ + static int i = 42; + extern int i; /* Error */ + return i; +} diff --git a/test/err/bug2162-static-extern-auto.c b/test/err/bug2162-static-extern-auto.c new file mode 100644 index 000000000..08d91e0e1 --- /dev/null +++ b/test/err/bug2162-static-extern-auto.c @@ -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; +} diff --git a/test/err/bug2162-static-static-extern.c b/test/err/bug2162-static-static-extern.c new file mode 100644 index 000000000..e0a536d6c --- /dev/null +++ b/test/err/bug2162-static-static-extern.c @@ -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; +} diff --git a/test/ref/bug1889-missing-identifier.cref b/test/ref/bug1889-missing-identifier.cref index cd3f76849..acaf53f94 100644 --- a/test/ref/bug1889-missing-identifier.cref +++ b/test/ref/bug1889-missing-identifier.cref @@ -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 diff --git a/test/val/bug2020-ok.c b/test/val/bug2020-ok.c new file mode 100644 index 000000000..6c52a9498 --- /dev/null +++ b/test/val/bug2020-ok.c @@ -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; +} diff --git a/test/val/bug2135.c b/test/val/bug2135.c new file mode 100644 index 000000000..1da0d2316 --- /dev/null +++ b/test/val/bug2135.c @@ -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 +#include + +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; +} diff --git a/test/todo/inline-asm-1489.c b/test/val/inline-asm-1489.c similarity index 84% rename from test/todo/inline-asm-1489.c rename to test/val/inline-asm-1489.c index 446831fcf..ec7597e01 100644 --- a/test/todo/inline-asm-1489.c +++ b/test/val/inline-asm-1489.c @@ -1,9 +1,11 @@ +#include #include #include #include #include +#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) { diff --git a/test/val/lib_common_htonl.c b/test/val/lib_common_htonl.c new file mode 100644 index 000000000..53a210a84 --- /dev/null +++ b/test/val/lib_common_htonl.c @@ -0,0 +1,34 @@ +/* + !!DESCRIPTION!! A small test for htons. + !!ORIGIN!! + !!LICENCE!! + !!AUTHOR!! Colin Leroy-Mira +*/ + +#include +#include +#include + +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; +} diff --git a/test/val/lib_common_htons.c b/test/val/lib_common_htons.c new file mode 100644 index 000000000..42bbb3d6b --- /dev/null +++ b/test/val/lib_common_htons.c @@ -0,0 +1,34 @@ +/* + !!DESCRIPTION!! A small test for htons. + !!ORIGIN!! + !!LICENCE!! + !!AUTHOR!! Colin Leroy-Mira +*/ + +#include +#include +#include + +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; +}