mirror of
https://github.com/cc65/cc65.git
synced 2024-12-27 00:29:31 +00:00
commit
1dcb21eaa7
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
12
cfg/cx16.cfg
12
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,
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -133,8 +133,7 @@ MKINC = $(GEOS) \
|
||||
|
||||
TARGETUTIL = apple2 \
|
||||
apple2enh \
|
||||
atari \
|
||||
geos-apple
|
||||
atari
|
||||
|
||||
GEOSDIRS = common \
|
||||
conio \
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -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
17
libsrc/telestrat/kbhit.s
Normal 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
|
@ -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 */
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
112
src/cc65/expr.c
112
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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
*/
|
||||
|
||||
|
@ -35,7 +35,7 @@
|
||||
|
||||
/* common */
|
||||
#include "chartype.h"
|
||||
|
||||
|
||||
/* cc65 */
|
||||
#include "ident.h"
|
||||
|
||||
|
@ -37,7 +37,7 @@
|
||||
#define LINEINFO_H
|
||||
|
||||
|
||||
|
||||
|
||||
/* common */
|
||||
#include "strbuf.h"
|
||||
|
||||
@ -50,7 +50,7 @@
|
||||
|
||||
|
||||
/* Input file structure */
|
||||
struct IFile;
|
||||
struct IFile;
|
||||
|
||||
|
||||
|
||||
|
@ -39,7 +39,7 @@
|
||||
|
||||
/* cc65 */
|
||||
#include "error.h"
|
||||
#include "loop.h"
|
||||
#include "loop.h"
|
||||
#include "stackptr.h"
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -228,7 +228,7 @@ static void DoCompare (const Type* lhs, const Type* rhs, typecmp_t* Result)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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");
|
||||
|
@ -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
83
test/val/bug1374.c
Normal 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
55
test/val/bug1397.c
Normal 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
41
test/val/bug1408.c
Normal 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
46
test/val/uneval.c
Normal 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user