diff --git a/cfg/atarixl-largehimem.cfg b/cfg/atarixl-largehimem.cfg index 5e60f32bd..38fb68db9 100644 --- a/cfg/atarixl-largehimem.cfg +++ b/cfg/atarixl-largehimem.cfg @@ -54,7 +54,7 @@ SEGMENTS { SYSCHKTRL: load = SYSCHKTRL, type = ro, optional = yes; SRPREPHDR: load = SRPREPHDR, type = ro; - LOWBSS: load = SRPREPCHNK, type = bss, define = yes; # shared btw. SRPREPCHNK and RAM, not zero initialized + LOWBSS: load = SRPREPCHNK, type = bss, define = yes; # shared btw. SRPREPCHNK and MAIN, not zero initialized SRPREP: load = SRPREPCHNK, type = rw, define = yes; SHADOW_RAM: load = SRPREPCHNK, run = HIDDEN_RAM, type = rw, define = yes, optional = yes; SHADOW_RAM2: load = SRPREPCHNK, run = HIDDEN_RAM, type = rw, define = yes, optional = yes; diff --git a/cfg/atarixl-overlay.cfg b/cfg/atarixl-overlay.cfg index 2bb4105cd..339228ea0 100644 --- a/cfg/atarixl-overlay.cfg +++ b/cfg/atarixl-overlay.cfg @@ -65,7 +65,7 @@ SEGMENTS { SYSCHKTRL: load = SYSCHKTRL, type = ro, optional = yes; SRPREPHDR: load = SRPREPHDR, type = ro; - LOWBSS: load = SRPREPCHNK, type = bss, define = yes; # shared btw. SRPREPCHNK and RAM, not zero initialized + LOWBSS: load = SRPREPCHNK, type = bss, define = yes; # shared btw. SRPREPCHNK and MAIN, not zero initialized SRPREP: load = SRPREPCHNK, type = rw, define = yes; SHADOW_RAM: load = SRPREPCHNK, run = HIDDEN_RAM, type = rw, define = yes, optional = yes; SHADOW_RAM2: load = SRPREPCHNK, run = HIDDEN_RAM2, type = rw, define = yes, optional = yes; diff --git a/cfg/atarixl-xex.cfg b/cfg/atarixl-xex.cfg index 6b6601c59..1b76855d0 100644 --- a/cfg/atarixl-xex.cfg +++ b/cfg/atarixl-xex.cfg @@ -48,7 +48,7 @@ SEGMENTS { EXTZP: load = ZP, type = zp, optional = yes; SYSCHK: load = SYSCHKCHNK, type = rw, define = yes, optional = yes; - LOWBSS: load = SRPREPCHNK, type = bss, define = yes; # shared btw. SRPREPCHNK and RAM, not zero initialized + LOWBSS: load = SRPREPCHNK, type = bss, define = yes; # shared btw. SRPREPCHNK and MAIN, not zero initialized SRPREP: load = SRPREPCHNK, type = rw, define = yes; SHADOW_RAM: load = SRPREPCHNK, run = HIDDEN_RAM, type = rw, define = yes, optional = yes; SHADOW_RAM2: load = SRPREPCHNK, run = HIDDEN_RAM2, type = rw, define = yes, optional = yes; diff --git a/cfg/atarixl.cfg b/cfg/atarixl.cfg index d4e466ae1..cece23555 100644 --- a/cfg/atarixl.cfg +++ b/cfg/atarixl.cfg @@ -52,7 +52,7 @@ SEGMENTS { SYSCHKTRL: load = SYSCHKTRL, type = ro, optional = yes; SRPREPHDR: load = SRPREPHDR, type = ro; - LOWBSS: load = SRPREPCHNK, type = bss, define = yes; # shared btw. SRPREPCHNK and RAM, not zero initialized + LOWBSS: load = SRPREPCHNK, type = bss, define = yes; # shared btw. SRPREPCHNK and MAIN, not zero initialized SRPREP: load = SRPREPCHNK, type = rw, define = yes; SHADOW_RAM: load = SRPREPCHNK, run = HIDDEN_RAM, type = rw, define = yes, optional = yes; SHADOW_RAM2: load = SRPREPCHNK, run = HIDDEN_RAM2, type = rw, define = yes, optional = yes; diff --git a/cfg/cx16-asm.cfg b/cfg/cx16-asm.cfg index c3c08aec3..92c9d96f7 100644 --- a/cfg/cx16-asm.cfg +++ b/cfg/cx16-asm.cfg @@ -22,9 +22,11 @@ SEGMENTS { EXEHDR: load = MAIN, type = ro, optional = yes; CODE: load = MAIN, type = ro; LOWCODE: load = MAIN, type = ro, optional = yes; + ONCE: load = MAIN, type = ro, optional = yes; RODATA: load = MAIN, type = ro; DATA: load = MAIN, type = rw; - BSS: load = MAIN, type = bss, define = yes; + INIT: load = MAIN, type = bss, optional = yes; + BSS: load = MAIN, type = bss, define = yes; } FEATURES { CONDES: type = constructor, diff --git a/cfg/cx16-bank.cfg b/cfg/cx16-bank.cfg index 36b0edb02..d3c2c02ae 100644 --- a/cfg/cx16-bank.cfg +++ b/cfg/cx16-bank.cfg @@ -16,8 +16,6 @@ MEMORY { HEADER: file = %O, define = yes, start = %S, size = $000D; MAIN: file = %O, define = yes, start = __HEADER_LAST__, size = __HIMEM__ - __HEADER_LAST__; BSS: file = "", start = __ONCE_RUN__, size = __HIMEM__ - __ONCE_RUN__ - __STACKSIZE__; -# BRAM00ADDR: file = "%O.00", start = __BANKRAMSTART__ - 2, size = $0002; -# BRAM00: file = "%O.00", start = __BANKRAMSTART__, size = __BANKRAMSIZE__; BRAM01ADDR: file = "%O.01", start = __BANKRAMSTART__ - 2, size = $0002; BRAM01: file = "%O.01", start = __BANKRAMSTART__, size = __BANKRAMSIZE__, bank = $01; BRAM02ADDR: file = "%O.02", start = __BANKRAMSTART__ - 2, size = $0002; @@ -36,64 +34,62 @@ MEMORY { BRAM08: file = "%O.08", start = __BANKRAMSTART__, size = __BANKRAMSIZE__, bank = $08; BRAM09ADDR: file = "%O.09", start = __BANKRAMSTART__ - 2, size = $0002; BRAM09: file = "%O.09", start = __BANKRAMSTART__, size = __BANKRAMSIZE__, bank = $09; - BRAM0AADDR: file = "%O.0a", start = __BANKRAMSTART__ - 2, size = $0002; - BRAM0A: file = "%O.0a", start = __BANKRAMSTART__, size = __BANKRAMSIZE__, bank = $0A; - BRAM0BADDR: file = "%O.0b", start = __BANKRAMSTART__ - 2, size = $0002; - BRAM0B: file = "%O.0b", start = __BANKRAMSTART__, size = __BANKRAMSIZE__, bank = $0B; - BRAM0CADDR: file = "%O.0c", start = __BANKRAMSTART__ - 2, size = $0002; - BRAM0C: file = "%O.0c", start = __BANKRAMSTART__, size = __BANKRAMSIZE__, bank = $0C; - BRAM0DADDR: file = "%O.0d", start = __BANKRAMSTART__ - 2, size = $0002; - BRAM0D: file = "%O.0d", start = __BANKRAMSTART__, size = __BANKRAMSIZE__, bank = $0D; - BRAM0EADDR: file = "%O.0e", start = __BANKRAMSTART__ - 2, size = $0002; - BRAM0E: file = "%O.0e", start = __BANKRAMSTART__, size = __BANKRAMSIZE__, bank = $0E; - BRAM0FADDR: file = "%O.0f", start = __BANKRAMSTART__ - 2, size = $0002; - BRAM0F: file = "%O.0f", start = __BANKRAMSTART__, size = __BANKRAMSIZE__, bank = $0F; + BRAM0AADDR: file = "%O.0A", start = __BANKRAMSTART__ - 2, size = $0002; + BRAM0A: file = "%O.0A", start = __BANKRAMSTART__, size = __BANKRAMSIZE__, bank = $0A; + BRAM0BADDR: file = "%O.0B", start = __BANKRAMSTART__ - 2, size = $0002; + BRAM0B: file = "%O.0B", start = __BANKRAMSTART__, size = __BANKRAMSIZE__, bank = $0B; + BRAM0CADDR: file = "%O.0C", start = __BANKRAMSTART__ - 2, size = $0002; + BRAM0C: file = "%O.0C", start = __BANKRAMSTART__, size = __BANKRAMSIZE__, bank = $0C; + BRAM0DADDR: file = "%O.0D", start = __BANKRAMSTART__ - 2, size = $0002; + BRAM0D: file = "%O.0D", start = __BANKRAMSTART__, size = __BANKRAMSIZE__, bank = $0D; + BRAM0EADDR: file = "%O.0E", start = __BANKRAMSTART__ - 2, size = $0002; + BRAM0E: file = "%O.0E", start = __BANKRAMSTART__, size = __BANKRAMSIZE__, bank = $0E; + BRAM0FADDR: file = "%O.0F", start = __BANKRAMSTART__ - 2, size = $0002; + BRAM0F: file = "%O.0F", start = __BANKRAMSTART__, size = __BANKRAMSIZE__, bank = $0F; } SEGMENTS { ZEROPAGE: load = ZP, type = zp; - EXTZP: load = ZP, type = zp, optional = yes; + EXTZP: load = ZP, type = zp, optional = yes; LOADADDR: load = LOADADDR, type = ro; EXEHDR: load = HEADER, type = ro; - STARTUP: load = MAIN, type = ro; - LOWCODE: load = MAIN, type = ro, optional = yes; + STARTUP: load = MAIN, type = ro, optional = yes; + LOWCODE: load = MAIN, type = ro, optional = yes; CODE: load = MAIN, type = ro; RODATA: load = MAIN, type = ro; DATA: load = MAIN, type = rw; - INIT: load = MAIN, type = rw; - ONCE: load = MAIN, type = ro, define = yes; - BSS: load = BSS, type = bss, define = yes; -# BRAM00ADDR: load = BRAM00ADDR, type = ro, optional = yes; -# BANKRAM00: load = BRAM00, type = rw, define = yes, optional = yes; - BRAM01ADDR: load = BRAM01ADDR, type = ro, optional = yes; - BANKRAM01: load = BRAM01, type = rw, define = yes, optional = yes; - BRAM02ADDR: load = BRAM02ADDR, type = ro, optional = yes; - BANKRAM02: load = BRAM02, type = rw, define = yes, optional = yes; - BRAM03ADDR: load = BRAM03ADDR, type = ro, optional = yes; - BANKRAM03: load = BRAM03, type = rw, define = yes, optional = yes; - BRAM04ADDR: load = BRAM04ADDR, type = ro, optional = yes; - BANKRAM04: load = BRAM04, type = rw, define = yes, optional = yes; - BRAM05ADDR: load = BRAM05ADDR, type = ro, optional = yes; - BANKRAM05: load = BRAM05, type = rw, define = yes, optional = yes; - BRAM06ADDR: load = BRAM06ADDR, type = ro, optional = yes; - BANKRAM06: load = BRAM06, type = rw, define = yes, optional = yes; - BRAM07ADDR: load = BRAM07ADDR, type = ro, optional = yes; - BANKRAM07: load = BRAM07, type = rw, define = yes, optional = yes; - BRAM08ADDR: load = BRAM08ADDR, type = ro, optional = yes; - BANKRAM08: load = BRAM08, type = rw, define = yes, optional = yes; - BRAM09ADDR: load = BRAM09ADDR, type = ro, optional = yes; - BANKRAM09: load = BRAM09, type = rw, define = yes, optional = yes; - BRAM0AADDR: load = BRAM0AADDR, type = ro, optional = yes; - BANKRAM0A: load = BRAM0A, type = rw, define = yes, optional = yes; - BRAM0BADDR: load = BRAM0BADDR, type = ro, optional = yes; - BANKRAM0B: load = BRAM0B, type = rw, define = yes, optional = yes; - BRAM0CADDR: load = BRAM0CADDR, type = ro, optional = yes; - BANKRAM0C: load = BRAM0C, type = rw, define = yes, optional = yes; - BRAM0DADDR: load = BRAM0DADDR, type = ro, optional = yes; - BANKRAM0D: load = BRAM0D, type = rw, define = yes, optional = yes; - BRAM0EADDR: load = BRAM0EADDR, type = ro, optional = yes; - BANKRAM0E: load = BRAM0E, type = rw, define = yes, optional = yes; - BRAM0FADDR: load = BRAM0FADDR, type = ro, optional = yes; - BANKRAM0F: load = BRAM0F, type = rw, define = yes, optional = yes; + INIT: load = MAIN, type = rw, optional = yes; + ONCE: load = MAIN, type = ro, define = yes; + BSS: load = BSS, type = bss, define = yes; + BRAM01ADDR: load = BRAM01ADDR, type = ro, optional = yes; + BANKRAM01: load = BRAM01, type = rw, optional = yes, define = yes; + BRAM02ADDR: load = BRAM02ADDR, type = ro, optional = yes; + BANKRAM02: load = BRAM02, type = rw, optional = yes, define = yes; + BRAM03ADDR: load = BRAM03ADDR, type = ro, optional = yes; + BANKRAM03: load = BRAM03, type = rw, optional = yes, define = yes; + BRAM04ADDR: load = BRAM04ADDR, type = ro, optional = yes; + BANKRAM04: load = BRAM04, type = rw, optional = yes, define = yes; + BRAM05ADDR: load = BRAM05ADDR, type = ro, optional = yes; + BANKRAM05: load = BRAM05, type = rw, optional = yes, define = yes; + BRAM06ADDR: load = BRAM06ADDR, type = ro, optional = yes; + BANKRAM06: load = BRAM06, type = rw, optional = yes, define = yes; + BRAM07ADDR: load = BRAM07ADDR, type = ro, optional = yes; + BANKRAM07: load = BRAM07, type = rw, optional = yes, define = yes; + BRAM08ADDR: load = BRAM08ADDR, type = ro, optional = yes; + BANKRAM08: load = BRAM08, type = rw, optional = yes, define = yes; + BRAM09ADDR: load = BRAM09ADDR, type = ro, optional = yes; + BANKRAM09: load = BRAM09, type = rw, optional = yes, define = yes; + BRAM0AADDR: load = BRAM0AADDR, type = ro, optional = yes; + BANKRAM0A: load = BRAM0A, type = rw, optional = yes, define = yes; + BRAM0BADDR: load = BRAM0BADDR, type = ro, optional = yes; + BANKRAM0B: load = BRAM0B, type = rw, optional = yes, define = yes; + BRAM0CADDR: load = BRAM0CADDR, type = ro, optional = yes; + BANKRAM0C: load = BRAM0C, type = rw, optional = yes, define = yes; + BRAM0DADDR: load = BRAM0DADDR, type = ro, optional = yes; + BANKRAM0D: load = BRAM0D, type = rw, optional = yes, define = yes; + BRAM0EADDR: load = BRAM0EADDR, type = ro, optional = yes; + BANKRAM0E: load = BRAM0E, type = rw, optional = yes, define = yes; + BRAM0FADDR: load = BRAM0FADDR, type = ro, optional = yes; + BANKRAM0F: load = BRAM0F, type = rw, optional = yes, define = yes; } FEATURES { CONDES: type = constructor, diff --git a/cfg/cx16.cfg b/cfg/cx16.cfg index 72fc2fe91..4b6025fb6 100644 --- a/cfg/cx16.cfg +++ b/cfg/cx16.cfg @@ -16,17 +16,17 @@ MEMORY { } SEGMENTS { ZEROPAGE: load = ZP, type = zp; - EXTZP: load = ZP, type = zp, optional = yes; + EXTZP: load = ZP, type = zp, optional = yes; LOADADDR: load = LOADADDR, type = ro; EXEHDR: load = HEADER, type = ro; - STARTUP: load = MAIN, type = ro; - LOWCODE: load = MAIN, type = ro, optional = yes; + STARTUP: load = MAIN, type = ro, optional = yes; + LOWCODE: load = MAIN, type = ro, optional = yes; CODE: load = MAIN, type = ro; RODATA: load = MAIN, type = ro; DATA: load = MAIN, type = rw; - INIT: load = MAIN, type = rw; - ONCE: load = MAIN, type = ro, define = yes; - BSS: load = BSS, type = bss, define = yes; + INIT: load = MAIN, type = rw, optional = yes; + ONCE: load = MAIN, type = ro, define = yes; + BSS: load = BSS, type = bss, define = yes; } FEATURES { CONDES: type = constructor, diff --git a/doc/atari5200.sgml b/doc/atari5200.sgml index aff212b15..c7e5be73e 100644 --- a/doc/atari5200.sgml +++ b/doc/atari5200.sgml @@ -30,7 +30,7 @@ information. Binary format

-The standard binary output format generated by the linker for the Atari 5200 target +The binary output format generated by the linker for the Atari 5200 target is a cartridge image. It is of course possible to change this behaviour by using a modified startup file and linker config. @@ -219,10 +219,58 @@ you cannot use any of the following functions (and a few others): Other hints

+CAR format

+ AtariROMMaker ( ) can be used to create a Changing the splash screen

+ +The 5200 ROM displays a splash screen at startup with the name of the +game and the copyright year. The year information has a 'Year-2000' +problem, the first two digits are fixed in the ROM and are always "19". + +Changing the game name

+ +The runtime library provides a default game name which is "cc65 +compiled". To change that, one has to link a file which puts data into +the " +.export __CART_NAME__: absolute = 1 +.macpack atari +.segment "CARTNAME" + scrcode " cc" + .byte '6' + 32, '5' + 32 ; use playfield 1 + scrcode " compiled" + + +'Changing the copyright year / changing the cartridge type

+ +The century is hard-coded to 1900 by the ROM. + +There are two digits which can be changed. For example "92" will give +"1992" on the screen. + +The default used by the runtime library is + + +.export __CART_YEAR__: absolute = 1 +.segment "CARTYEAR" + .byte '9' + 32,'8' + 32 ; "98", using playfield 1 + + +If the second byte of the year in the License

diff --git a/doc/ld65.sgml b/doc/ld65.sgml index cba06fef4..538948fc0 100644 --- a/doc/ld65.sgml +++ b/doc/ld65.sgml @@ -921,9 +921,8 @@ name="6502 binary relocation format specification">). It is defined like this: } -The other format available is the Atari (xex) segmented file format, this is -the standard format used by Atari DOS 2.0 and upward file managers in the Atari -8-bit computers, and it is defined like this: +The other format available is the Atari segmented file format (xex), this is +the standard format used by Atari DOS 2.0 and upwards, and it is defined like this: FILES { @@ -1010,7 +1009,8 @@ The segment This attribute tells the linker into which segment the table should be - placed. If the segment does not exist, it is created. + placed. If the segment does not exist in any object file, it is created + in the final object code. type @@ -1059,7 +1059,7 @@ The . @@ -1140,6 +1140,19 @@ The builtin config files do contain segments that have a special meaning for the compiler and the libraries that come with it. If you replace the builtin config files, you will need the following information. +INIT

+ +The INIT segment is some kind of 'bss' segment since it contains +uninitialized data. Unlike .bss itself, its contents aren't +initialized to zero at program startup . It's mostly used by +constructors in the startup code. An example for the use of the INIT +segment is saving/restoring the zero page area used by cc65. + +LOWCODE

+ +For the LOWCODE segment, it is guaranteed that it won't be banked out, so it +is reachable at any time by interrupt handlers or similar. + ONCE

The ONCE segment is used for initialization code run only once before @@ -1147,11 +1160,6 @@ execution reaches main() - provided that the program runs in RAM. You may for example add the ONCE segment to the heap in really memory constrained systems. -LOWCODE

- -For the LOWCODE segment, it is guaranteed that it won't be banked out, so it -is reachable at any time by interrupt handlers or similar. - STARTUP

This segment contains the startup code which initializes the C software stack diff --git a/include/atari.h b/include/atari.h index f5916a284..86c7b9706 100644 --- a/include/atari.h +++ b/include/atari.h @@ -6,10 +6,11 @@ /* */ /* */ /* */ -/* (C) 2000-2019 Mark Keates */ +/* (C) 2000-2021 Mark Keates */ /* Freddy Offenga */ /* Christian Groessler */ /* Bill Kendrick */ +/* et al. */ /* */ /* */ /* This software is provided 'as-is', without any expressed or implied */ @@ -219,7 +220,7 @@ /* Color register functions */ /*****************************************************************************/ -extern void __fastcall__ _setcolor (unsigned char color_reg, unsigned char hue, unsigned char luminace); +extern void __fastcall__ _setcolor (unsigned char color_reg, unsigned char hue, unsigned char luminance); extern void __fastcall__ _setcolor_low (unsigned char color_reg, unsigned char color_value); extern unsigned char __fastcall__ _getcolor (unsigned char color_reg); diff --git a/include/cbm.h b/include/cbm.h index 5bcef8e60..cceb76b1b 100644 --- a/include/cbm.h +++ b/include/cbm.h @@ -191,6 +191,8 @@ unsigned char cbm_k_acptr (void); unsigned char cbm_k_basin (void); void __fastcall__ cbm_k_bsout (unsigned char C); unsigned char __fastcall__ cbm_k_chkin (unsigned char FN); +unsigned char cbm_k_chrin (void); +void __fastcall__ cbm_k_chrout (unsigned char C); void __fastcall__ cbm_k_ciout (unsigned char C); unsigned char __fastcall__ cbm_k_ckout (unsigned char FN); void cbm_k_clall (void); @@ -295,7 +297,15 @@ unsigned char __fastcall__ cbm_readdir (unsigned char lfn, /* Reads one directory line into cbm_dirent structure. ** Returns 0 if reading directory-line was successful. ** Returns non-zero if reading directory failed, or no more file-names to read. -** Returns 2 on last line. Then, l_dirent->size = the number of "blocks free." +** Returns 2 on last line. Then, l_dirent->size = the number of "blocks free", +** "blocks used", or "mb free". Return codes: +** 0 = read file-name +** 1 = couldn't read directory +** 2 = read "blocks free", "blocks used", or "mb free" +** 3 = couldn't find start of file-name +** 4 = couldn't find end of file-name +** 5 = couldn't read file-type +** 6 = premature end of file */ void __fastcall__ cbm_closedir (unsigned char lfn); diff --git a/libsrc/Makefile b/libsrc/Makefile index d9ddb3ccd..3fac513af 100644 --- a/libsrc/Makefile +++ b/libsrc/Makefile @@ -133,8 +133,7 @@ MKINC = $(GEOS) \ TARGETUTIL = apple2 \ apple2enh \ - atari \ - geos-apple + atari GEOSDIRS = common \ conio \ diff --git a/libsrc/apple2/targetutil/Makefile.inc b/libsrc/apple2/targetutil/Makefile.inc index d9d727b0a..b53139a3d 100644 --- a/libsrc/apple2/targetutil/Makefile.inc +++ b/libsrc/apple2/targetutil/Makefile.inc @@ -1,9 +1,17 @@ -DEPS += ../libwrk/$(TARGET)/loader.d +DEPS += ../libwrk/$(TARGET)/convert.d \ + ../libwrk/$(TARGET)/loader.d + +../libwrk/$(TARGET)/convert.o: $(SRCDIR)/targetutil/convert.c | ../libwrk/$(TARGET) + $(COMPILE_recipe) ../libwrk/$(TARGET)/loader.o: $(SRCDIR)/targetutil/loader.s | ../libwrk/$(TARGET) $(ASSEMBLE_recipe) +../target/$(TARGET)/util/convert.system: ../libwrk/$(TARGET)/convert.o ../lib/$(TARGET).lib | ../target/$(TARGET)/util + $(LD65) -o $@ -C $(TARGET)-system.cfg $^ + ../target/$(TARGET)/util/loader.system: ../libwrk/$(TARGET)/loader.o $(SRCDIR)/targetutil/loader.cfg | ../target/$(TARGET)/util $(LD65) -o $@ -C $(filter %.cfg,$^) $(filter-out %.cfg,$^) -$(TARGET): ../target/$(TARGET)/util/loader.system +$(TARGET): ../target/$(TARGET)/util/convert.system \ + ../target/$(TARGET)/util/loader.system diff --git a/libsrc/geos-apple/targetutil/convert.c b/libsrc/apple2/targetutil/convert.c similarity index 100% rename from libsrc/geos-apple/targetutil/convert.c rename to libsrc/apple2/targetutil/convert.c diff --git a/libsrc/cbm/c_basin.s b/libsrc/cbm/c_basin.s index da925a1a4..c2211e9ce 100644 --- a/libsrc/cbm/c_basin.s +++ b/libsrc/cbm/c_basin.s @@ -2,14 +2,16 @@ ; Ullrich von Bassewitz, 03.06.1999 ; ; unsigned char cbm_k_basin (void); +; unsigned char cbm_k_chrin (void); ; .include "cbm.inc" - .export _cbm_k_basin + .export _cbm_k_basin, _cbm_k_chrin _cbm_k_basin: +_cbm_k_chrin: jsr BASIN ldx #0 ; Clear high byte rts diff --git a/libsrc/cbm/c_bsout.s b/libsrc/cbm/c_bsout.s index 104878453..cec46bf90 100644 --- a/libsrc/cbm/c_bsout.s +++ b/libsrc/cbm/c_bsout.s @@ -2,10 +2,12 @@ ; Ullrich von Bassewitz, 03.06.1999 ; ; void __fastcall__ cbm_k_bsout (unsigned char C); +; void __fastcall__ cbm_k_chrout (unsigned char C); ; .include "cbm.inc" - .export _cbm_k_bsout + .export _cbm_k_bsout, _cbm_k_chrout -_cbm_k_bsout = BSOUT +_cbm_k_bsout := BSOUT +_cbm_k_chrout := CHROUT diff --git a/libsrc/cbm/cbm_dir.c b/libsrc/cbm/cbm_dir.c index 8f31c502a..4b8927f98 100644 --- a/libsrc/cbm/cbm_dir.c +++ b/libsrc/cbm/cbm_dir.c @@ -6,6 +6,7 @@ /* 2009-10-10 -- Version 0.3 */ /* 2011-04-07 -- Version 0.4, groepaz */ /* 2011-04-14 -- Version 0.5, Greg King */ +/* 2021-02-15 -- Version 0.6, Greg King */ /* Tested with floppy-drive and IDE64 devices. */ /* Not tested with messed (buggy) directory listings. */ @@ -29,7 +30,7 @@ unsigned char cbm_opendir (unsigned char lfn, unsigned char device, ...) va_list ap; const char* name = "$"; - /* The name used in cbm_open may optionally be passed */ + /* The name used in cbm_open() optionally may be passed */ if (__argsize__ == 4) { va_start (ap, device); name = va_arg (ap, const char*); @@ -76,9 +77,10 @@ unsigned char __fastcall__ cbm_readdir (unsigned char lfn, register struct cbm_d byte = cbm_k_basin(); switch (byte) { - - /* "B" BLOCKS FREE. */ + /* "B" BLOCKS FREE/USED. */ + /* "M" MB FREE. */ case 'b': + case 'm': /* Read until end; careless callers might call us again. */ while (!cbm_k_readst()) { cbm_k_basin(); @@ -168,7 +170,6 @@ unsigned char __fastcall__ cbm_readdir (unsigned char lfn, register struct cbm_d } rv = 0; - goto ret_val; } } diff --git a/libsrc/cbm/readdir.c b/libsrc/cbm/readdir.c index 8d6968977..1512edc4e 100644 --- a/libsrc/cbm/readdir.c +++ b/libsrc/cbm/readdir.c @@ -1,5 +1,7 @@ /* -** Ullrich von Bassewitz, 2012-05-30. Based on code by Groepaz. +** Based on code by Groepaz. +** 2012-05-30, Ullrich von Bassewitz +** 2021-02-15, Greg King */ @@ -52,12 +54,14 @@ struct dirent* __fastcall__ readdir (register DIR* dir) /* Bump the directory offset and include the bytes for line-link and size */ dir->off += count + 4; - /* End of directory is reached if the buffer contains "blocks free". It is - ** sufficient here to check for the leading 'b'. buffer will contain at - ** least one byte if we come here. + /* End of directory is reached if the buffer contains "blocks free/used" or + ** "mb free.". It is sufficient here to check for the leading 'b' and 'm'. + ** buffer will contain at least one byte if we come here. */ - if (buffer[0] == 'b') { - goto exitpoint; + switch (buffer[0]) { + case 'b': + case 'm': + goto exitpoint; } /* Parse the buffer for the filename and file type */ @@ -67,7 +71,6 @@ struct dirent* __fastcall__ readdir (register DIR* dir) b = buffer; while (i < count) { switch (s) { - case 0: /* Searching for start of file name */ if (*b == '"') { @@ -127,6 +130,3 @@ struct dirent* __fastcall__ readdir (register DIR* dir) exitpoint: return 0; } - - - diff --git a/libsrc/geos-apple/targetutil/Makefile.inc b/libsrc/geos-apple/targetutil/Makefile.inc deleted file mode 100644 index 3d366f913..000000000 --- a/libsrc/geos-apple/targetutil/Makefile.inc +++ /dev/null @@ -1,14 +0,0 @@ -DEPS += ../libwrk/$(TARGET)/convert.d - -../libwrk/$(TARGET)/convert.o: TARGET = apple2enh - -../libwrk/$(TARGET)/convert.o: $(SRCDIR)/targetutil/convert.c | ../libwrk/$(TARGET) - $(COMPILE_recipe) - -../lib/apple2enh.lib: - @$(MAKE) --no-print-directory apple2enh - -../target/$(TARGET)/util/convert.system: ../libwrk/$(TARGET)/convert.o ../lib/apple2enh.lib | ../target/$(TARGET)/util - $(LD65) -o $@ -C apple2enh-system.cfg $^ - -$(TARGET): ../target/$(TARGET)/util/convert.system diff --git a/libsrc/telestrat/kbhit.s b/libsrc/telestrat/kbhit.s new file mode 100644 index 000000000..54e4bf4d8 --- /dev/null +++ b/libsrc/telestrat/kbhit.s @@ -0,0 +1,17 @@ +; +; Jede, 2021-02-01 +; +; int kbhit (void); +; + + .export _kbhit + + .include "telestrat.inc" + +_kbhit: + BRK_TELEMON XRD0 + ldx #$00 + txa + rol + eor #$01 + rts diff --git a/src/cc65/assignment.c b/src/cc65/assignment.c index 09a10a642..737d059a0 100644 --- a/src/cc65/assignment.c +++ b/src/cc65/assignment.c @@ -169,7 +169,7 @@ void Assignment (ExprDesc* Expr) /* cc65 does not have full support for handling structs or unions. Since ** assigning structs is one of the more useful operations from this family, ** allow it here. - ** Note: IsClassStruct() is also true for union types. + ** Note: IsClassStruct() is also true for union types. */ if (IsClassStruct (ltype)) { /* Copy the struct or union by value */ diff --git a/src/cc65/codegen.c b/src/cc65/codegen.c index 3ca9d81e6..bf7c900ab 100644 --- a/src/cc65/codegen.c +++ b/src/cc65/codegen.c @@ -2822,7 +2822,8 @@ void g_div (unsigned flags, unsigned long val) } /* Negate the result as long as val < 0, even if val == -1 and no - ** shift was generated. */ + ** shift was generated. + */ if (Negation) { g_neg (flags); } diff --git a/src/cc65/codeinfo.c b/src/cc65/codeinfo.c index e0cda84e9..90d4f4d68 100644 --- a/src/cc65/codeinfo.c +++ b/src/cc65/codeinfo.c @@ -493,22 +493,28 @@ fncls_t GetFuncInfo (const char* Name, unsigned int* Use, unsigned int* Chg) ** registers. */ *Use = REG_EAXY; - } else if (D->ParamCount > 0 && + } else if ((D->ParamCount > 0 || + (D->Flags & FD_EMPTY) != 0) && (AutoCDecl ? IsQualFastcall (E->Type) : !IsQualCDecl (E->Type))) { /* Will use registers depending on the last param. If the last - ** param has incomplete type, just assume __EAX__. + ** param has incomplete type, or if the function has not been + ** prototyped yet, just assume __EAX__. */ - switch (SizeOf (D->LastParam->Type)) { - case 1u: - *Use = REG_A; - break; - case 2u: - *Use = REG_AX; - break; - default: - *Use = REG_EAX; + if (D->LastParam != 0) { + switch (SizeOf(D->LastParam->Type)) { + case 1u: + *Use = REG_A; + break; + case 2u: + *Use = REG_AX; + break; + default: + *Use = REG_EAX; + } + } else { + *Use = REG_EAX; } } else { /* Will not use any registers */ diff --git a/src/cc65/codeopt.c b/src/cc65/codeopt.c index 3c10183e4..29fa79d26 100644 --- a/src/cc65/codeopt.c +++ b/src/cc65/codeopt.c @@ -380,7 +380,7 @@ void ListOptSteps (FILE* F) /* List all optimization steps */ { unsigned I; - + fprintf (F, "any\n"); for (I = 0; I < OPTFUNC_COUNT; ++I) { if (OptFuncs[I]->Func != 0) { diff --git a/src/cc65/codeoptutil.c b/src/cc65/codeoptutil.c index 3df762eeb..2f79b131b 100644 --- a/src/cc65/codeoptutil.c +++ b/src/cc65/codeoptutil.c @@ -356,8 +356,9 @@ static int Affected (LoadRegInfo* LRI, const CodeEntry* E) } if ((LRI->Flags & LI_CHECK_Y) != 0) { - /* If we don't know what memory location could have been used by Y, - ** we just assume all. */ + /* If we don't know what memory location could have been + ** used by Y, we just assume all. + */ if (YE == 0 || (YE->ArgOff == E->ArgOff && strcmp (YE->ArgBase, E->ArgBase) == 0)) { @@ -375,8 +376,9 @@ static int Affected (LoadRegInfo* LRI, const CodeEntry* E) /* Otherwise unaffected */ goto L_Result; } - /* We could've check further for more cases where the load target isn't - ** modified, but for now let's save the trouble and just play it safe. + /* We could've check further for more cases where the load target + ** isn't modified, but for now let's save the trouble and just play + ** it safe. */ goto L_Affected; } @@ -678,7 +680,7 @@ void SetDontRemoveEntryFlag (LoadRegInfo* LRI) if (LRI->Flags & LI_DONT_REMOVE) { if (LRI->LoadEntry != 0) { LRI->LoadEntry->Flags |= CEF_DONT_REMOVE; - + /* If the load requires Y, then Y shouldn't be removed either */ if (LRI->LoadYEntry != 0) { LRI->LoadYEntry->Flags |= CEF_DONT_REMOVE; @@ -1080,7 +1082,7 @@ void AddOpHigh (StackOpData* D, opc_t OPC, LoadInfo* LI, int KeepResult) } else { - if ((LI->A.Flags & LI_CHECK_Y) == 0) { + if ((LI->X.Flags & LI_CHECK_Y) == 0) { /* ldy #const */ X = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (LI->X.Offs), 0, D->OpEntry->LI); } else { @@ -1094,7 +1096,7 @@ void AddOpHigh (StackOpData* D, opc_t OPC, LoadInfo* LI, int KeepResult) X = NewCodeEntry (OPC, AM65_ZP_INDY, "sp", 0, D->OpEntry->LI); } else { /* opc src,y */ - X = NewCodeEntry (OPC, LI->A.LoadEntry->AM, LI->A.LoadEntry->Arg, 0, D->OpEntry->LI); + X = NewCodeEntry (OPC, LI->X.LoadEntry->AM, LI->X.LoadEntry->Arg, 0, D->OpEntry->LI); } InsertEntry (D, X, D->IP++); } @@ -2562,7 +2564,7 @@ int BackupArgAfter (CodeSeg* S, BackupInfo* B, int Idx, const CodeEntry* E, Coll static int LoadAAt (CodeSeg* S, int Idx, const LoadRegInfo* LRI, Collection* Indices, int After) /* Reload into A the same arg according to LoadRegInfo before or after Idx -** depending on the After param. +** depending on the After param. */ { CodeEntry* E; @@ -2582,7 +2584,7 @@ static int LoadAAt (CodeSeg* S, int Idx, const LoadRegInfo* LRI, Collection* Ind CHECK (E != 0); O = CS_GetEntry (S, OldIdx); - + /* We only recognize opc with an arg for now, as well as a special case for ldaxysp */ if ((E->OPC != OP65_JSR || strcmp (E->Arg, "ldaxysp") == 0) && E->AM != AM65_BRA && E->AM != AM65_IMP) { @@ -2645,7 +2647,7 @@ static int LoadAAt (CodeSeg* S, int Idx, const LoadRegInfo* LRI, Collection* Ind static int LoadXAt (CodeSeg* S, int Idx, const LoadRegInfo* LRI, Collection* Indices, int After) /* Reload into X the same arg according to LoadRegInfo before or after Idx -** depending on the After param. +** depending on the After param. */ { CodeEntry* E; @@ -2744,7 +2746,7 @@ static int LoadXAt (CodeSeg* S, int Idx, const LoadRegInfo* LRI, Collection* Ind static int LoadYAt (CodeSeg* S, int Idx, const LoadRegInfo* LRI, Collection* Indices, int After) /* Reload into Y the same arg according to LoadRegInfo before or after Idx -** depending on the After param. +** depending on the After param. */ { CodeEntry* E; diff --git a/src/cc65/coptind.c b/src/cc65/coptind.c index f3e17fc87..a080cfb20 100644 --- a/src/cc65/coptind.c +++ b/src/cc65/coptind.c @@ -990,7 +990,7 @@ unsigned OptTransfers4 (CodeSeg* S) ** isn't used later, and we have an address mode match, we can ** replace the transfer by a load and remove the initial load. */ - if ((GetRegInfo (S, I, LoadEntry->Chg & REG_ALL) & + if ((GetRegInfo (S, I, LoadEntry->Chg & REG_ALL) & LoadEntry->Chg & REG_ALL) == 0 && (LoadEntry->AM == AM65_ABS || LoadEntry->AM == AM65_ZP || @@ -1252,7 +1252,7 @@ unsigned OptPushPop2 (CodeSeg* S) /* Go into searching mode again */ State = Searching; } - } else if ((E->Info & OF_BRA) == 0 && + } else if ((E->Info & OF_BRA) == 0 && (E->Info & OF_STORE) == 0 && E->OPC != OP65_NOP && E->OPC != OP65_TSX) { @@ -1500,14 +1500,11 @@ unsigned OptShiftBack (CodeSeg* S) (N->OPC == OP65_LSR || N->OPC == OP65_ROR) && !CE_HasLabel (N)) { - CheckStates = PSTATE_ZN; - if (N->OPC == OP65_LSR && !PStatesAreClear (E->RI->Out.PFlags, PSTATE_C)) { CheckStates |= REG_A; } - if ((GetRegInfo (S, I+2, CheckStates) & CheckStates) == 0) { /* Remove the shifts */ diff --git a/src/cc65/coptptrload.h b/src/cc65/coptptrload.h index 84d7cc19f..d4e0e2ed4 100644 --- a/src/cc65/coptptrload.h +++ b/src/cc65/coptptrload.h @@ -233,7 +233,7 @@ unsigned OptPtrLoad11 (CodeSeg* S); */ unsigned OptPtrLoad12 (CodeSeg* S); -/* Search for the sequence: +/* Search for the sequence: ** ** lda regbank+n ** ldx regbank+n+1 diff --git a/src/cc65/coptstop.c b/src/cc65/coptstop.c index 77b79281b..01d0b039c 100644 --- a/src/cc65/coptstop.c +++ b/src/cc65/coptstop.c @@ -453,6 +453,7 @@ static unsigned Opt_staxspidx (StackOpData* D) /* Optimize the staxspidx sequence */ { CodeEntry* X; + const char* Arg = 0; /* Check if we're using a register variable */ if (!IsRegVar (D)) { @@ -469,7 +470,7 @@ static unsigned Opt_staxspidx (StackOpData* D) if (RegValIsKnown (D->OpEntry->RI->In.RegY)) { /* Value of Y is known */ - const char* Arg = MakeHexArg (D->OpEntry->RI->In.RegY + 1); + Arg = MakeHexArg (D->OpEntry->RI->In.RegY + 1); X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, D->OpEntry->LI); } else { X = NewCodeEntry (OP65_INY, AM65_IMP, 0, 0, D->OpEntry->LI); @@ -478,7 +479,7 @@ static unsigned Opt_staxspidx (StackOpData* D) if (RegValIsKnown (D->OpEntry->RI->In.RegX)) { /* Value of X is known */ - const char* Arg = MakeHexArg (D->OpEntry->RI->In.RegX); + Arg = MakeHexArg (D->OpEntry->RI->In.RegX); X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, D->OpEntry->LI); } else { /* Value unknown */ @@ -493,7 +494,12 @@ static unsigned Opt_staxspidx (StackOpData* D) /* If we remove staxspidx, we must restore the Y register to what the ** function would return. */ - X = NewCodeEntry (OP65_LDY, AM65_IMM, "$00", 0, D->OpEntry->LI); + if (RegValIsKnown (D->OpEntry->RI->In.RegY)) { + Arg = MakeHexArg (D->OpEntry->RI->In.RegY); + X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, D->OpEntry->LI); + } else { + X = NewCodeEntry (OP65_DEY, AM65_IMP, 0, 0, D->OpEntry->LI); + } InsertEntry (D, X, D->OpIndex+5); /* Remove the push and the call to the staxspidx function */ diff --git a/src/cc65/datatype.c b/src/cc65/datatype.c index 413007a85..6e42057dc 100644 --- a/src/cc65/datatype.c +++ b/src/cc65/datatype.c @@ -462,7 +462,7 @@ Type* GetImplicitFuncType (void) Type* T = TypeAlloc (3); /* func/returns int/terminator */ /* Prepare the function descriptor */ - F->Flags = FD_EMPTY | FD_VARIADIC; + F->Flags = FD_EMPTY; F->SymTab = &EmptySymTab; F->TagTab = &EmptySymTab; @@ -755,8 +755,9 @@ unsigned SizeOf (const Type* T) return T->A.U; /* Beware: There's a chance that this triggers problems in other parts - of the compiler. The solution is to fix the callers, because calling - SizeOf() with a function type as argument is bad. */ + ** of the compiler. The solution is to fix the callers, because calling + ** SizeOf() with a function type as argument is bad. + */ case T_FUNC: return 0; /* Size of function is unknown */ diff --git a/src/cc65/declare.c b/src/cc65/declare.c index 08739f333..d952d1049 100644 --- a/src/cc65/declare.c +++ b/src/cc65/declare.c @@ -1522,7 +1522,7 @@ static Type* ParamTypeCvt (Type* T) } else if (IsTypeFunc (T)) { Tmp = PointerTo (T); } - + if (Tmp != 0) { /* Do several fixes on qualifiers */ FixQualifiers (Tmp); @@ -1786,7 +1786,7 @@ static FuncDesc* ParseFuncDecl (void) ** won't always get to know the parameter sizes here and may do that later. */ F->Flags |= FD_INCOMPLETE_PARAM; - + /* Leave the lexical level remembering the symbol tables */ RememberFunctionLevel (F); diff --git a/src/cc65/expr.c b/src/cc65/expr.c index 0cf650d3b..09a7a1f39 100644 --- a/src/cc65/expr.c +++ b/src/cc65/expr.c @@ -251,6 +251,42 @@ static unsigned typeadjust (ExprDesc* lhs, ExprDesc* rhs, int NoPush) +static void LimitExprValue (ExprDesc* Expr) +/* Limit the constant value of the expression to the range of its type */ +{ + switch (GetUnderlyingTypeCode (Expr->Type)) { + case T_INT: + case T_SHORT: + Expr->IVal = (int16_t)Expr->IVal; + break; + + case T_UINT: + case T_USHORT: + case T_PTR: + case T_ARRAY: + Expr->IVal = (uint16_t)Expr->IVal; + break; + + case T_LONG: + case T_ULONG: + /* No need to do anything */ + break; + + case T_SCHAR: + Expr->IVal = (int8_t)Expr->IVal; + break; + + case T_UCHAR: + Expr->IVal = (uint8_t)Expr->IVal; + break; + + default: + Internal ("hie_internal: constant result type %s\n", GetFullTypeName (Expr->Type)); + } +} + + + static const GenDesc* FindGen (token_t Tok, const GenDesc* Table) /* Find a token in a generator table */ { @@ -376,6 +412,9 @@ void DoneDeferredOps (void) static void DeferInc (const ExprDesc* Expr) /* Defer the post-inc and put it in a queue */ { + if (ED_IsUneval (Expr)) { + return; + } DeferredOp* Op = xmalloc (sizeof (DeferredOp)); memcpy (&Op->Expr, Expr, sizeof (ExprDesc)); Op->OpType = DOT_INC; @@ -387,6 +426,9 @@ static void DeferInc (const ExprDesc* Expr) static void DeferDec (const ExprDesc* Expr) /* Defer the post-dec and put it in a queue */ { + if (ED_IsUneval (Expr)) { + return; + } DeferredOp* Op = xmalloc (sizeof (DeferredOp)); memcpy (&Op->Expr, Expr, sizeof (ExprDesc)); Op->OpType = DOT_DEC; @@ -1171,16 +1213,16 @@ static void Primary (ExprDesc* E) /* IDENT is either an auto-declared function or an undefined variable. */ if (CurTok.Tok == TOK_LPAREN) { - /* C99 doesn't allow calls to undefined functions, so + /* C99 doesn't allow calls to undeclared functions, so ** generate an error and otherwise a warning. Declare a ** function returning int. For that purpose, prepare a ** function signature for a function having an empty param ** list and returning int. */ if (IS_Get (&Standard) >= STD_C99) { - Error ("Call to undefined function '%s'", Ident); + Error ("Call to undeclared function '%s'", Ident); } else { - Warning ("Call to undefined function '%s'", Ident); + Warning ("Call to undeclared function '%s'", Ident); } Sym = AddGlobalSym (Ident, GetImplicitFuncType(), SC_EXTERN | SC_REF | SC_FUNC); E->Type = Sym->Type; @@ -2159,15 +2201,19 @@ static void UnaryOp (ExprDesc* Expr) ED_MakeConstAbsInt (Expr, 1); } - /* Check for a constant expression */ + /* Check for a constant numeric expression */ if (ED_IsConstAbs (Expr)) { - /* Value is constant */ + /* Value is numeric */ switch (Tok) { case TOK_MINUS: Expr->IVal = -Expr->IVal; break; case TOK_PLUS: break; case TOK_COMP: Expr->IVal = ~Expr->IVal; break; default: Internal ("Unexpected token: %d", Tok); } + + /* Limit the calculated value to the range of its type */ + LimitExprValue (Expr); + } else { /* Value is not constant */ LoadExpr (CF_NONE, Expr); @@ -2218,7 +2264,7 @@ void hie10 (ExprDesc* Expr) NextToken (); BoolExpr (hie10, Expr); if (ED_IsConstAbs (Expr)) { - /* Constant expression */ + /* Constant numeric expression */ Expr->IVal = !Expr->IVal; } else if (ED_IsAddrExpr (Expr)) { /* Address != NULL, so !Address == 0 */ @@ -2509,6 +2555,9 @@ static void hie_internal (const GenDesc* Ops, /* List of generators */ } } + /* Limit the calculated value to the range of its type */ + LimitExprValue (Expr); + } else if (lconst && (Gen->Flags & GEN_COMM) && !rconst) { /* If the LHS constant is an int that fits into an unsigned char, change the ** codegen type to unsigned char. If the RHS is also an unsigned char, then @@ -2744,6 +2793,9 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ } } + /* Get rid of unwanted flags */ + ED_MakeConstBool (Expr, Expr->IVal); + /* If the result is constant, this is suspicious when not in ** preprocessor mode. */ @@ -2796,7 +2848,7 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ } /* Determine the type of the operation. */ - if (IsTypeChar (Expr->Type) && rconst) { + if (IsTypeChar (Expr->Type) && rconst && (!LeftSigned || RightSigned)) { /* Left side is unsigned char, right side is constant. ** Determine the minimum and maximum values @@ -2809,20 +2861,6 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ LeftMin = 0; LeftMax = 255; } - /* An integer value is always represented as a signed in the - ** ExprDesc structure. This may lead to false results below, - ** if it is actually unsigned, but interpreted as signed - ** because of the representation. Fortunately, in this case, - ** the actual value doesn't matter, since it's always greater - ** than what can be represented in a char. So correct the - ** value accordingly. - */ - if (!RightSigned && Expr2.IVal < 0) { - /* Correct the value so it is an unsigned. It will then - ** anyway match one of the cases below. - */ - Expr2.IVal = LeftMax + 1; - } /* Comparing a char against a constant may have a constant ** result. Please note: It is not possible to remove the code @@ -2888,7 +2926,7 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ ** since the right side constant is in a valid range. */ flags |= (CF_CHAR | CF_FORCECHAR); - if (!LeftSigned) { + if (!LeftSigned || !RightSigned) { flags |= CF_UNSIGNED; } @@ -2902,7 +2940,7 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ if (rconst) { flags |= CF_FORCECHAR; } - if (!LeftSigned) { + if (!LeftSigned || !RightSigned) { flags |= CF_UNSIGNED; } } else { @@ -2910,11 +2948,11 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ flags |= g_typeadjust (ltype, rtype); } - /* If the left side is an unsigned and the right is a constant, - ** we may be able to change the compares to something more + /* If the comparison is made as unsigned types and the right is a + ** constant, we may be able to change the compares to something more ** effective. */ - if (!LeftSigned && rconst) { + if ((!LeftSigned || !RightSigned) && rconst) { switch (Tok) { @@ -3042,6 +3080,9 @@ static void parseadd (ExprDesc* Expr) /* Integer addition */ Expr->IVal += Expr2.IVal; typeadjust (Expr, &Expr2, 1); + + /* Limit the calculated value to the range of its type */ + LimitExprValue (Expr); } else { /* OOPS */ Error ("Invalid operands for binary operator '+'"); @@ -3130,6 +3171,9 @@ static void parseadd (ExprDesc* Expr) flags = CF_INT; } + /* Array and function types must be converted to pointer types */ + Expr->Type = PtrConversion (Expr->Type); + /* Result is an rvalue in primary register */ ED_FinalizeRValLoad (Expr); } @@ -3225,7 +3269,7 @@ static void parseadd (ExprDesc* Expr) ED_FinalizeRValLoad (Expr); } - /* Condition codes not set */ + /* Condition code not set */ ED_MarkAsUntested (Expr); } @@ -3301,7 +3345,7 @@ static void parsesub (ExprDesc* Expr) Error ("Incompatible pointer types"); } else { Expr->IVal = (Expr->IVal - Expr2.IVal) / - CheckedPSizeOf (lhst); + (long)CheckedPSizeOf (lhst); } /* Operate on pointers, result type is an integer */ Expr->Type = type_int; @@ -3309,14 +3353,14 @@ static void parsesub (ExprDesc* Expr) /* Integer subtraction */ typeadjust (Expr, &Expr2, 1); Expr->IVal -= Expr2.IVal; + + /* Limit the calculated value to the range of its type */ + LimitExprValue (Expr); } else { /* OOPS */ Error ("Invalid operands for binary operator '-'"); } - /* Result is constant, condition codes not set */ - ED_MarkAsUntested (Expr); - } else { /* Left hand side is not constant, right hand side is. @@ -3358,8 +3402,6 @@ static void parsesub (ExprDesc* Expr) /* Result is an rvalue in the primary register */ ED_FinalizeRValLoad (Expr); - ED_MarkAsUntested (Expr); - } } else { @@ -3412,8 +3454,10 @@ static void parsesub (ExprDesc* Expr) /* Result is an rvalue in the primary register */ ED_FinalizeRValLoad (Expr); - ED_MarkAsUntested (Expr); } + + /* Condition code not set */ + ED_MarkAsUntested (Expr); } diff --git a/src/cc65/exprdesc.c b/src/cc65/exprdesc.c index e82d0fafc..f5d8cd779 100644 --- a/src/cc65/exprdesc.c +++ b/src/cc65/exprdesc.c @@ -261,7 +261,7 @@ ExprDesc* ED_MakeConstBool (ExprDesc* Expr, long Value) { Expr->Sym = 0; Expr->Type = type_bool; - Expr->Flags = E_LOC_NONE | E_RTYPE_RVAL | (Expr->Flags & E_HAVE_MARKS); + Expr->Flags = E_LOC_NONE | E_RTYPE_RVAL | (Expr->Flags & E_MASK_KEEP_MAKE); Expr->Name = 0; Expr->IVal = Value; Expr->FVal = FP_D_Make (0.0); diff --git a/src/cc65/exprdesc.h b/src/cc65/exprdesc.h index 810d68965..e1bf3117f 100644 --- a/src/cc65/exprdesc.h +++ b/src/cc65/exprdesc.h @@ -73,7 +73,7 @@ enum { ** - ref-load doesn't change the rval/lval category of the expression, ** while rval-load converts it to an rvalue if it wasn't. ** - In practice, ref-load is unimplemented, and can be simulated with - ** adding E_ADDRESS_OF temporaily through LoadExpr + FinalizeLoad, + ** adding E_ADDRESS_OF temporaily through LoadExpr + FinalizeLoad, ** whilst val-load is done with LoadExpr + FinalizeRValLoad. ** ** E_LOC_NONE -- ref-load -> + E_LOADED (int rvalue) @@ -142,7 +142,7 @@ enum { ** than it are usually consided "side-effects" in this regard. ** - The compiler front end cannot know things determined by the linker, ** such as the actual address of an object with static storage. What it - ** can know is categorized as "compiler-known" here. + ** can know is categorized as "compiler-known" here. ** - The concept "immutable" here means that once something is determined ** (not necessarily by the compiler), it will never change. This is not ** the same meaning as the "constant" word in the C standard. @@ -299,7 +299,7 @@ INLINE int ED_IsLocExpr (const ExprDesc* Expr) #if defined(HAVE_INLINE) INLINE int ED_IsLocLiteral (const ExprDesc* Expr) /* Return true if the expression is a string from the literal pool */ -{ +{ return (Expr->Flags & E_MASK_LOC) == E_LOC_LITERAL; } #else diff --git a/src/cc65/hexval.h b/src/cc65/hexval.h index 0361ee0cf..68ea5e40f 100644 --- a/src/cc65/hexval.h +++ b/src/cc65/hexval.h @@ -45,7 +45,7 @@ unsigned HexVal (int C); -/* Convert a hex digit into a value. The function will emit an error for +/* Convert a hex digit into a value. The function will emit an error for ** invalid hex digits. */ diff --git a/src/cc65/ident.c b/src/cc65/ident.c index 7748095c7..dc59c4868 100644 --- a/src/cc65/ident.c +++ b/src/cc65/ident.c @@ -35,7 +35,7 @@ /* common */ #include "chartype.h" - + /* cc65 */ #include "ident.h" diff --git a/src/cc65/lineinfo.h b/src/cc65/lineinfo.h index 8dbe06846..f365b4f01 100644 --- a/src/cc65/lineinfo.h +++ b/src/cc65/lineinfo.h @@ -37,7 +37,7 @@ #define LINEINFO_H - + /* common */ #include "strbuf.h" @@ -50,7 +50,7 @@ /* Input file structure */ -struct IFile; +struct IFile; diff --git a/src/cc65/loop.c b/src/cc65/loop.c index c15c37a79..f6c53ddc4 100644 --- a/src/cc65/loop.c +++ b/src/cc65/loop.c @@ -39,7 +39,7 @@ /* cc65 */ #include "error.h" -#include "loop.h" +#include "loop.h" #include "stackptr.h" diff --git a/src/cc65/pragma.c b/src/cc65/pragma.c index 1ea86545d..2dd923cf1 100644 --- a/src/cc65/pragma.c +++ b/src/cc65/pragma.c @@ -460,7 +460,7 @@ static void SegNamePragma (StrBuf* B, segment_t Seg) Warning ("Invalid address size for segment!"); } } - + /* Set the new name and optionally address size */ if (Push) { PushSegName (Seg, Name); diff --git a/src/cc65/reginfo.h b/src/cc65/reginfo.h index 28b948e04..2066ab505 100644 --- a/src/cc65/reginfo.h +++ b/src/cc65/reginfo.h @@ -102,7 +102,7 @@ #define ZNREG_A REG_A #define ZNREG_X REG_X #define ZNREG_Y REG_Y -#define ZNREG_TMP1 REG_TMP1 +#define ZNREG_TMP1 REG_TMP1 #define ZNREG_PTR1_LO REG_PTR1_LO #define ZNREG_PTR1_HI REG_PTR1_HI #define ZNREG_PTR2_LO REG_PTR2_LO diff --git a/src/cc65/scanstrbuf.c b/src/cc65/scanstrbuf.c index bbee569d2..2e3be8854 100644 --- a/src/cc65/scanstrbuf.c +++ b/src/cc65/scanstrbuf.c @@ -185,7 +185,7 @@ int SB_GetSym (StrBuf* B, StrBuf* Ident, const char* SpecialChars) SB_AppendChar (Ident, C); SB_Skip (B); C = SB_Peek (B); - } while (IsIdent (C) || IsDigit (C) || + } while (IsIdent (C) || IsDigit (C) || (C != '\0' && strchr (SpecialChars, C) != 0)); SB_Terminate (Ident); return 1; diff --git a/src/cc65/shiftexpr.c b/src/cc65/shiftexpr.c index 0c69e96e5..d7b43dde2 100644 --- a/src/cc65/shiftexpr.c +++ b/src/cc65/shiftexpr.c @@ -193,7 +193,7 @@ void ShiftExpr (struct ExprDesc* Expr) ED_IsLocQuasiConst (Expr) && Expr2.IVal >= 8) { - Type* OldType; + Type* OldType; /* Increase the address by one and decrease the shift count */ ++Expr->IVal; diff --git a/src/cc65/symtab.c b/src/cc65/symtab.c index 56c868b2a..db2b04f17 100644 --- a/src/cc65/symtab.c +++ b/src/cc65/symtab.c @@ -518,7 +518,7 @@ SymEntry FindStructField (const Type* T, const char* Name) */ if (Struct->V.S.SymTab) { Entry = FindSymInTable (Struct->V.S.SymTab, Name, HashStr (Name)); - + if (Entry != 0) { Offs = Entry->V.Offs; } @@ -732,7 +732,7 @@ SymEntry* AddEnumSym (const char* Name, unsigned Flags, const Type* Type, SymTab CurTagTab = FailSafeTab; } } - + if (Entry == 0) { /* Create a new entry */ @@ -817,7 +817,7 @@ SymEntry* AddStructSym (const char* Name, unsigned Flags, unsigned Size, SymTabl CurTagTab = FailSafeTab; } } - + if (Entry == 0) { /* Create a new entry */ @@ -1116,7 +1116,7 @@ SymEntry* AddLocalSym (const char* Name, const Type* T, unsigned Flags, int Offs } } } - + if (Entry == 0) { /* Create a new entry */ Entry = NewSymEntry (Name, Flags); @@ -1159,12 +1159,13 @@ SymEntry* AddLocalSym (const char* Name, const Type* T, unsigned Flags, int Offs SymEntry* AddGlobalSym (const char* Name, const Type* T, unsigned Flags) /* Add an external or global symbol to the symbol table and return the entry */ { - /* Use the global symbol table */ + /* Start from the local symbol table */ SymTable* Tab = SymTab; /* Do we have an entry with this name already? */ SymEntry* Entry = FindSymInTree (Tab, Name); if (Entry) { + /* We have a symbol with this name already */ if (HandleSymRedefinition (Entry, T, Flags)) { Entry = 0; @@ -1215,8 +1216,11 @@ SymEntry* AddGlobalSym (const char* Name, const Type* T, unsigned Flags) /* Use the fail-safe table for fictitious symbols */ Tab = FailSafeTab; } - } - + + } else if ((Flags & (SC_EXTERN | SC_FUNC)) != 0) { + /* Add the new declaration to the global symbol table instead */ + Tab = SymTab0; + } if (Entry == 0 || Entry->Owner != Tab) { /* Create a new entry */ diff --git a/src/cc65/testexpr.c b/src/cc65/testexpr.c index eefaeb74a..e5db488de 100644 --- a/src/cc65/testexpr.c +++ b/src/cc65/testexpr.c @@ -32,7 +32,7 @@ /*****************************************************************************/ - + /* cc65 */ #include "codegen.h" #include "error.h" @@ -63,7 +63,7 @@ unsigned Test (unsigned Label, int Invert) /* Read a boolean expression */ BoolExpr (hie0, &Expr); - /* Check for a constant expression */ + /* Check for a constant numeric expression */ if (ED_IsConstAbs (&Expr)) { /* Append deferred inc/dec at sequence point */ diff --git a/src/cc65/typecmp.c b/src/cc65/typecmp.c index 1f4643e73..f204b9a0b 100644 --- a/src/cc65/typecmp.c +++ b/src/cc65/typecmp.c @@ -228,7 +228,7 @@ static void DoCompare (const Type* lhs, const Type* rhs, typecmp_t* Result) return; } } - } + } } } diff --git a/test/misc/Makefile b/test/misc/Makefile index 81a09c693..7a1b82d5f 100644 --- a/test/misc/Makefile +++ b/test/misc/Makefile @@ -101,13 +101,12 @@ $(WORKDIR)/bug1263.$1.$2.prg: bug1263.c | $(WORKDIR) $(NOT) $(CC65) -t sim$2 -$1 -o $$@ $$< $(NULLERR) # this one requires --std=c89, it fails with --std=c99 -# it fails currently at runtime $(WORKDIR)/bug1265.$1.$2.prg: bug1265.c | $(WORKDIR) $(if $(QUIET),echo misc/bug1265.$1.$2.prg) $(CC65) --standard c89 -t sim$2 -$1 -o $$(@:.prg=.s) $$< $(NULLERR) $(CA65) -t sim$2 -o $$(@:.prg=.o) $$(@:.prg=.s) $(NULLERR) $(LD65) -t sim$2 -o $$@ $$(@:.prg=.o) sim$2.lib $(NULLERR) - $(NOT) $(SIM65) $(SIM65FLAGS) $$@ $(NULLOUT) $(NULLERR) + $(SIM65) $(SIM65FLAGS) $$@ $(NULLOUT) $(NULLERR) # should compile, but then hangs in an endless loop $(WORKDIR)/endless.$1.$2.prg: endless.c | $(WORKDIR) diff --git a/test/misc/bug1265.c b/test/misc/bug1265.c index 469946739..36d1459a7 100644 --- a/test/misc/bug1265.c +++ b/test/misc/bug1265.c @@ -14,11 +14,9 @@ int main (void) { int x, n; sprintf (str1, "%p\n", &x); - puts(str1); x = 1234; n = f1 (x); sprintf (str2, "%p\n", &x); - puts(str2); if (strcmp(str1, str2)) { puts("not equal"); @@ -30,11 +28,9 @@ int main (void) { } sprintf (str1, "%p\n", &x); - puts(str1); x = 2345; n = f2 (x); sprintf (str2, "%p\n", &x); - puts(str2); if (strcmp(str1, str2)) { puts("not equal"); diff --git a/test/todo/bug1310.c b/test/val/bug1310.c similarity index 84% rename from test/todo/bug1310.c rename to test/val/bug1310.c index 936145928..306c91fb6 100644 --- a/test/todo/bug1310.c +++ b/test/val/bug1310.c @@ -68,6 +68,20 @@ int main (void) failures++; } + if (-32768U != 32768U) { + fprintf (stderr, "Expected -32768U == 32768U, got: %ld\n", (long)-32768U); + failures++; + } + if (~32767U != 32768U) { + fprintf (stderr, "Expected ~32767U == 32768U, got: %ld\n", (long)~32767U); + failures++; + } + + if ((long*)0x1000 - (long*)0x2000 >= 0) { + fprintf (stderr, "Expected (long*)0x1000 - (long*)0x2000 < 0, got: %ld\n", (long*)0x1000 - (long*)0x2000); + failures++; + } printf ("failures: %u\n", failures); + return failures; } diff --git a/test/val/bug1374.c b/test/val/bug1374.c new file mode 100644 index 000000000..b55e75fee --- /dev/null +++ b/test/val/bug1374.c @@ -0,0 +1,83 @@ + +/* test for bug#1374 */ + +#include +#include + +static int res = 0; + +int test1(void) +{ + uint8_t x = 0x89; + uint8_t y = 0xab; + uint16_t z = (x << 8) | y; + printf("%x\n", z); + return (z == 0x89ab) ? 0 : 1; +} + +int test1b(void) +{ + uint8_t x = 0x89; + uint8_t y = 0xab; + uint16_t z = (x * 256) | y; + printf("%x\n", z); + return (z == 0x89ab) ? 0 : 1; +} + +int test2(void) +{ + uint16_t x = 0x8900; + uint8_t y = 0xab; + uint16_t z = x | y; + printf("%x\n", z); + return (z == 0x89ab) ? 0 : 1; +} + +int test3(void) +{ + uint16_t x = 0x89; + uint8_t y = 0xab; + uint16_t z = (x << 8) | y; + printf("%x\n", z); + return (z == 0x89ab) ? 0 : 1; +} + +int test3b(void) +{ + uint16_t x = 0x89; + uint8_t y = 0xab; + uint16_t z = (x * 256) | y; + printf("%x\n", z); + return (z == 0x89ab) ? 0 : 1; +} + +int test4(void) +{ + uint8_t x = 0x89; + uint16_t y = 0xab; + uint16_t z = (x << 8) | y; + printf("%x\n", z); + return (z == 0x89ab) ? 0 : 1; +} + +int test4b(void) +{ + uint8_t x = 0x89; + uint16_t y = 0xab; + uint16_t z = (x * 256) | y; + printf("%x\n", z); + return (z == 0x89ab) ? 0 : 1; +} + +int main(void) +{ + res |= test1(); + res |= test2(); + res |= test3(); + res |= test4(); + res |= test1b(); + res |= test3b(); + res |= test4b(); + printf("res: %d\n", res); + return res; +} diff --git a/test/val/bug1397.c b/test/val/bug1397.c new file mode 100644 index 000000000..4f8fb8697 --- /dev/null +++ b/test/val/bug1397.c @@ -0,0 +1,55 @@ + +/* bug #1937 - Incorrect Behavior Related to OptBoolTrans */ + +#include + +unsigned char c; +int *p; + +void f1(void) { + int i = 1; + int *pa = (int *)0xaaaa; + int *pb = (int *)0xbbbb; + + p = (i == 0) ? pa : pb; + c = 0x5a; +} + + +struct data_t { + unsigned char c; + int *p; +}; + +struct data_t data; + +void f2(void) { + int i = 1; + int *pa = (int *)0xcccc; + int *pb = (int *)0xdddd; + struct data_t *po = &data; + + po->p = (i == 0) ? pa : pb; + po->c = 0xa5; +} + +int ret = 0; + +int main(void) { + f1(); + if (c != 0x5a) { + ret++; + } + printf("c: %hhx\n", c); + printf("p: %p\n", p); + f2(); + if (data.c != 0xa5) { + ret++; + } + printf("c: %hhx\n", data.c); + printf("p: %p\n", data.p); + + printf("failures: %d\n", ret); + return ret; +} + diff --git a/test/val/bug1408.c b/test/val/bug1408.c new file mode 100644 index 000000000..8ecc1be68 --- /dev/null +++ b/test/val/bug1408.c @@ -0,0 +1,41 @@ +/* Bug #1408: Signed char type comparisons with unsigned numeric constants */ + +#include + +static int failures = 0; +static signed char x = -1; + +int main(void) +{ + if (!(x > -2u)) { + printf("x > -2u should be true\n"); + ++failures; + } + if (!(x > 0u)) { + printf("x > 0u should be true\n"); + ++failures; + } + if (!(x > 255u)) { + printf("x > 255u should be true\n"); + ++failures; + } + + if (!(-2u < x)) { + printf("-2u < x should be true\n"); + ++failures; + } + if (!(0u < x)) { + printf("0u < x should be true\n"); + ++failures; + } + if (!(255u < x)) { + printf("255u < x should be true\n"); + ++failures; + } + + if (failures != 0) { + printf("Failures: %d\n", failures); + } + + return failures; +} diff --git a/test/val/uneval.c b/test/val/uneval.c new file mode 100644 index 000000000..50e00973a --- /dev/null +++ b/test/val/uneval.c @@ -0,0 +1,46 @@ +/* + Copyright 2021, The cc65 Authors + + This software is provided "as-is", without any express 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. +*/ + +/* + Test of deferred operations in unevaluated context resulted from 'sizeof' and + short-circuited code-paths in AND, OR and tenary operations. + + https://github.com/cc65/cc65/issues/1406 +*/ + +#include + +int main(void) +{ + int i = 0; + int j = 0; + + sizeof(i++ | j--); + 0 && (i++ | j--); + 1 || (i++ | j--); + 0 ? i++ | j-- : 0; + 1 ? 0 : i++ | j--; + + if (i != 0 || j != 0) { + printf("i = %d, j = %d\n", i, j); + printf("Failures: %d\n", i - j); + } + return i - j; +}