1
0
mirror of https://github.com/cc65/cc65.git synced 2024-12-27 00:29:31 +00:00

Merge pull request #2 from cc65/master

Update
This commit is contained in:
polluks2 2021-03-04 09:09:46 +01:00 committed by GitHub
commit 1dcb21eaa7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
51 changed files with 589 additions and 214 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -30,7 +30,7 @@ information.
<sect>Binary format<p>
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):
<sect>Other hints<p>
<sect1>CAR format<p>
AtariROMMaker (<url url="https://www.wudsn.com/index.php/productions-atari800/tools/atarirommaker"> )
can be used to create a <tt/.CAR/ file from the binary ROM image cc65 generates.
This might be more convenient when working with emulators.
<sect1>Changing the splash screen<p>
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".
<sect2>Changing the game name<p>
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 "<tt/CARTNAME/" segment.
For reference, here's the default version used by the cc65 libary:
<tscreen><verb>
.export __CART_NAME__: absolute = 1
.macpack atari
.segment "CARTNAME"
scrcode " cc"
.byte '6' + 32, '5' + 32 ; use playfield 1
scrcode " compiled"
</verb></tscreen>
'<tt/__CART_NAME__/' needs to be defined in order that the linker is
satisfied and doesn't try to include the version of the runtime library.
20 bytes are available in the <tt/CARTNAME/ segment (one line) for the
game/program name.
<sect2>Changing the copyright year / changing the cartridge type<p>
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
<tscreen><verb>
.export __CART_YEAR__: absolute = 1
.segment "CARTYEAR"
.byte '9' + 32,'8' + 32 ; "98", using playfield 1
</verb></tscreen>
If the second byte of the year in the <tt/CARTYEAR/ segment is 255,
the cartridge is seen as a 'diagnostic' cartridge, and the splash
screen and most of the other startup initializations are bypassed.
<sect>License<p>

View File

@ -921,9 +921,8 @@ name="6502 binary relocation format specification">). It is defined like this:
}
</verb></tscreen>
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:
<tscreen><verb>
FILES {
@ -1010,7 +1009,8 @@ The <tt/CONDES/ feature has several attributes:
<tag><tt>segment</tt></tag>
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.
<tag><tt>type</tt></tag>
@ -1059,7 +1059,7 @@ The <tt/CONDES/ feature has several attributes:
Without specifying the <tt/CONDES/ feature, the linker will not create any
tables, even if there are <tt/condes/ entries in the object files.
For more information see the <tt/.CONDES/ command in the <url
For more information, see the <tt/.CONDES/ command in the <url
url="ca65.html" name="ca65 manual">.
@ -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.
<sect1>INIT<p>
The INIT segment is some kind of 'bss' segment since it contains
uninitialized data. Unlike <tt>.bss</tt> 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.
<sect1>LOWCODE<p>
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.
<sect1>ONCE<p>
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.
<sect1>LOWCODE<p>
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.
<sect1>STARTUP<p>
This segment contains the startup code which initializes the C software stack

View File

@ -6,10 +6,11 @@
/* */
/* */
/* */
/* (C) 2000-2019 Mark Keates <markk@dendrite.co.uk> */
/* (C) 2000-2021 Mark Keates <markk@dendrite.co.uk> */
/* Freddy Offenga <taf_offenga@yahoo.com> */
/* Christian Groessler <chris@groessler.org> */
/* Bill Kendrick <nbs@sonic.net> */
/* 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);

View File

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

View File

@ -133,8 +133,7 @@ MKINC = $(GEOS) \
TARGETUTIL = apple2 \
apple2enh \
atari \
geos-apple
atari
GEOSDIRS = common \
conio \

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

17
libsrc/telestrat/kbhit.s Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -35,7 +35,7 @@
/* common */
#include "chartype.h"
/* cc65 */
#include "ident.h"

View File

@ -37,7 +37,7 @@
#define LINEINFO_H
/* common */
#include "strbuf.h"
@ -50,7 +50,7 @@
/* Input file structure */
struct IFile;
struct IFile;

View File

@ -39,7 +39,7 @@
/* cc65 */
#include "error.h"
#include "loop.h"
#include "loop.h"
#include "stackptr.h"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -228,7 +228,7 @@ static void DoCompare (const Type* lhs, const Type* rhs, typecmp_t* Result)
return;
}
}
}
}
}
}

View File

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

View File

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

View File

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

83
test/val/bug1374.c Normal file
View File

@ -0,0 +1,83 @@
/* test for bug#1374 */
#include <stdint.h>
#include <stdio.h>
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;
}

55
test/val/bug1397.c Normal file
View File

@ -0,0 +1,55 @@
/* bug #1937 - Incorrect Behavior Related to OptBoolTrans */
#include <stdio.h>
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;
}

41
test/val/bug1408.c Normal file
View File

@ -0,0 +1,41 @@
/* Bug #1408: Signed char type comparisons with unsigned numeric constants */
#include <stdio.h>
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;
}

46
test/val/uneval.c Normal file
View File

@ -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 <stdio.h>
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;
}