@@ -54,7 +54,7 @@ SEGMENTS {
|
|||||||
SYSCHKTRL: load = SYSCHKTRL, type = ro, optional = yes;
|
SYSCHKTRL: load = SYSCHKTRL, type = ro, optional = yes;
|
||||||
|
|
||||||
SRPREPHDR: load = SRPREPHDR, type = ro;
|
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;
|
SRPREP: load = SRPREPCHNK, type = rw, define = yes;
|
||||||
SHADOW_RAM: load = SRPREPCHNK, run = HIDDEN_RAM, type = rw, define = yes, optional = 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;
|
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;
|
SYSCHKTRL: load = SYSCHKTRL, type = ro, optional = yes;
|
||||||
|
|
||||||
SRPREPHDR: load = SRPREPHDR, type = ro;
|
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;
|
SRPREP: load = SRPREPCHNK, type = rw, define = yes;
|
||||||
SHADOW_RAM: load = SRPREPCHNK, run = HIDDEN_RAM, type = rw, define = yes, optional = 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;
|
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;
|
EXTZP: load = ZP, type = zp, optional = yes;
|
||||||
|
|
||||||
SYSCHK: load = SYSCHKCHNK, type = rw, define = yes, 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;
|
SRPREP: load = SRPREPCHNK, type = rw, define = yes;
|
||||||
SHADOW_RAM: load = SRPREPCHNK, run = HIDDEN_RAM, type = rw, define = yes, optional = 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;
|
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;
|
SYSCHKTRL: load = SYSCHKTRL, type = ro, optional = yes;
|
||||||
|
|
||||||
SRPREPHDR: load = SRPREPHDR, type = ro;
|
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;
|
SRPREP: load = SRPREPCHNK, type = rw, define = yes;
|
||||||
SHADOW_RAM: load = SRPREPCHNK, run = HIDDEN_RAM, type = rw, define = yes, optional = 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;
|
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;
|
EXEHDR: load = MAIN, type = ro, optional = yes;
|
||||||
CODE: load = MAIN, type = ro;
|
CODE: load = MAIN, type = ro;
|
||||||
LOWCODE: load = MAIN, type = ro, optional = yes;
|
LOWCODE: load = MAIN, type = ro, optional = yes;
|
||||||
|
ONCE: load = MAIN, type = ro, optional = yes;
|
||||||
RODATA: load = MAIN, type = ro;
|
RODATA: load = MAIN, type = ro;
|
||||||
DATA: load = MAIN, type = rw;
|
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 {
|
FEATURES {
|
||||||
CONDES: type = constructor,
|
CONDES: type = constructor,
|
||||||
|
|||||||
@@ -16,8 +16,6 @@ MEMORY {
|
|||||||
HEADER: file = %O, define = yes, start = %S, size = $000D;
|
HEADER: file = %O, define = yes, start = %S, size = $000D;
|
||||||
MAIN: file = %O, define = yes, start = __HEADER_LAST__, size = __HIMEM__ - __HEADER_LAST__;
|
MAIN: file = %O, define = yes, start = __HEADER_LAST__, size = __HIMEM__ - __HEADER_LAST__;
|
||||||
BSS: file = "", start = __ONCE_RUN__, size = __HIMEM__ - __ONCE_RUN__ - __STACKSIZE__;
|
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;
|
BRAM01ADDR: file = "%O.01", start = __BANKRAMSTART__ - 2, size = $0002;
|
||||||
BRAM01: file = "%O.01", start = __BANKRAMSTART__, size = __BANKRAMSIZE__, bank = $01;
|
BRAM01: file = "%O.01", start = __BANKRAMSTART__, size = __BANKRAMSIZE__, bank = $01;
|
||||||
BRAM02ADDR: file = "%O.02", start = __BANKRAMSTART__ - 2, size = $0002;
|
BRAM02ADDR: file = "%O.02", start = __BANKRAMSTART__ - 2, size = $0002;
|
||||||
@@ -36,64 +34,62 @@ MEMORY {
|
|||||||
BRAM08: file = "%O.08", start = __BANKRAMSTART__, size = __BANKRAMSIZE__, bank = $08;
|
BRAM08: file = "%O.08", start = __BANKRAMSTART__, size = __BANKRAMSIZE__, bank = $08;
|
||||||
BRAM09ADDR: file = "%O.09", start = __BANKRAMSTART__ - 2, size = $0002;
|
BRAM09ADDR: file = "%O.09", start = __BANKRAMSTART__ - 2, size = $0002;
|
||||||
BRAM09: file = "%O.09", start = __BANKRAMSTART__, size = __BANKRAMSIZE__, bank = $09;
|
BRAM09: file = "%O.09", start = __BANKRAMSTART__, size = __BANKRAMSIZE__, bank = $09;
|
||||||
BRAM0AADDR: file = "%O.0a", start = __BANKRAMSTART__ - 2, size = $0002;
|
BRAM0AADDR: file = "%O.0A", start = __BANKRAMSTART__ - 2, size = $0002;
|
||||||
BRAM0A: file = "%O.0a", start = __BANKRAMSTART__, size = __BANKRAMSIZE__, bank = $0A;
|
BRAM0A: file = "%O.0A", start = __BANKRAMSTART__, size = __BANKRAMSIZE__, bank = $0A;
|
||||||
BRAM0BADDR: file = "%O.0b", start = __BANKRAMSTART__ - 2, size = $0002;
|
BRAM0BADDR: file = "%O.0B", start = __BANKRAMSTART__ - 2, size = $0002;
|
||||||
BRAM0B: file = "%O.0b", start = __BANKRAMSTART__, size = __BANKRAMSIZE__, bank = $0B;
|
BRAM0B: file = "%O.0B", start = __BANKRAMSTART__, size = __BANKRAMSIZE__, bank = $0B;
|
||||||
BRAM0CADDR: file = "%O.0c", start = __BANKRAMSTART__ - 2, size = $0002;
|
BRAM0CADDR: file = "%O.0C", start = __BANKRAMSTART__ - 2, size = $0002;
|
||||||
BRAM0C: file = "%O.0c", start = __BANKRAMSTART__, size = __BANKRAMSIZE__, bank = $0C;
|
BRAM0C: file = "%O.0C", start = __BANKRAMSTART__, size = __BANKRAMSIZE__, bank = $0C;
|
||||||
BRAM0DADDR: file = "%O.0d", start = __BANKRAMSTART__ - 2, size = $0002;
|
BRAM0DADDR: file = "%O.0D", start = __BANKRAMSTART__ - 2, size = $0002;
|
||||||
BRAM0D: file = "%O.0d", start = __BANKRAMSTART__, size = __BANKRAMSIZE__, bank = $0D;
|
BRAM0D: file = "%O.0D", start = __BANKRAMSTART__, size = __BANKRAMSIZE__, bank = $0D;
|
||||||
BRAM0EADDR: file = "%O.0e", start = __BANKRAMSTART__ - 2, size = $0002;
|
BRAM0EADDR: file = "%O.0E", start = __BANKRAMSTART__ - 2, size = $0002;
|
||||||
BRAM0E: file = "%O.0e", start = __BANKRAMSTART__, size = __BANKRAMSIZE__, bank = $0E;
|
BRAM0E: file = "%O.0E", start = __BANKRAMSTART__, size = __BANKRAMSIZE__, bank = $0E;
|
||||||
BRAM0FADDR: file = "%O.0f", start = __BANKRAMSTART__ - 2, size = $0002;
|
BRAM0FADDR: file = "%O.0F", start = __BANKRAMSTART__ - 2, size = $0002;
|
||||||
BRAM0F: file = "%O.0f", start = __BANKRAMSTART__, size = __BANKRAMSIZE__, bank = $0F;
|
BRAM0F: file = "%O.0F", start = __BANKRAMSTART__, size = __BANKRAMSIZE__, bank = $0F;
|
||||||
}
|
}
|
||||||
SEGMENTS {
|
SEGMENTS {
|
||||||
ZEROPAGE: load = ZP, type = zp;
|
ZEROPAGE: load = ZP, type = zp;
|
||||||
EXTZP: load = ZP, type = zp, optional = yes;
|
EXTZP: load = ZP, type = zp, optional = yes;
|
||||||
LOADADDR: load = LOADADDR, type = ro;
|
LOADADDR: load = LOADADDR, type = ro;
|
||||||
EXEHDR: load = HEADER, type = ro;
|
EXEHDR: load = HEADER, type = ro;
|
||||||
STARTUP: load = MAIN, type = ro;
|
STARTUP: load = MAIN, type = ro, optional = yes;
|
||||||
LOWCODE: load = MAIN, type = ro, optional = yes;
|
LOWCODE: load = MAIN, type = ro, optional = yes;
|
||||||
CODE: load = MAIN, type = ro;
|
CODE: load = MAIN, type = ro;
|
||||||
RODATA: load = MAIN, type = ro;
|
RODATA: load = MAIN, type = ro;
|
||||||
DATA: load = MAIN, type = rw;
|
DATA: load = MAIN, type = rw;
|
||||||
INIT: load = MAIN, type = rw;
|
INIT: load = MAIN, type = rw, optional = yes;
|
||||||
ONCE: load = MAIN, type = ro, define = yes;
|
ONCE: load = MAIN, type = ro, define = yes;
|
||||||
BSS: load = BSS, type = bss, define = yes;
|
BSS: load = BSS, type = bss, define = yes;
|
||||||
# BRAM00ADDR: load = BRAM00ADDR, type = ro, optional = yes;
|
BRAM01ADDR: load = BRAM01ADDR, type = ro, optional = yes;
|
||||||
# BANKRAM00: load = BRAM00, type = rw, define = yes, optional = yes;
|
BANKRAM01: load = BRAM01, type = rw, optional = yes, define = yes;
|
||||||
BRAM01ADDR: load = BRAM01ADDR, type = ro, optional = yes;
|
BRAM02ADDR: load = BRAM02ADDR, type = ro, optional = yes;
|
||||||
BANKRAM01: load = BRAM01, type = rw, define = yes, optional = yes;
|
BANKRAM02: load = BRAM02, type = rw, optional = yes, define = yes;
|
||||||
BRAM02ADDR: load = BRAM02ADDR, type = ro, optional = yes;
|
BRAM03ADDR: load = BRAM03ADDR, type = ro, optional = yes;
|
||||||
BANKRAM02: load = BRAM02, type = rw, define = yes, optional = yes;
|
BANKRAM03: load = BRAM03, type = rw, optional = yes, define = yes;
|
||||||
BRAM03ADDR: load = BRAM03ADDR, type = ro, optional = yes;
|
BRAM04ADDR: load = BRAM04ADDR, type = ro, optional = yes;
|
||||||
BANKRAM03: load = BRAM03, type = rw, define = yes, optional = yes;
|
BANKRAM04: load = BRAM04, type = rw, optional = yes, define = yes;
|
||||||
BRAM04ADDR: load = BRAM04ADDR, type = ro, optional = yes;
|
BRAM05ADDR: load = BRAM05ADDR, type = ro, optional = yes;
|
||||||
BANKRAM04: load = BRAM04, type = rw, define = yes, optional = yes;
|
BANKRAM05: load = BRAM05, type = rw, optional = yes, define = yes;
|
||||||
BRAM05ADDR: load = BRAM05ADDR, type = ro, optional = yes;
|
BRAM06ADDR: load = BRAM06ADDR, type = ro, optional = yes;
|
||||||
BANKRAM05: load = BRAM05, type = rw, define = yes, optional = yes;
|
BANKRAM06: load = BRAM06, type = rw, optional = yes, define = yes;
|
||||||
BRAM06ADDR: load = BRAM06ADDR, type = ro, optional = yes;
|
BRAM07ADDR: load = BRAM07ADDR, type = ro, optional = yes;
|
||||||
BANKRAM06: load = BRAM06, type = rw, define = yes, optional = yes;
|
BANKRAM07: load = BRAM07, type = rw, optional = yes, define = yes;
|
||||||
BRAM07ADDR: load = BRAM07ADDR, type = ro, optional = yes;
|
BRAM08ADDR: load = BRAM08ADDR, type = ro, optional = yes;
|
||||||
BANKRAM07: load = BRAM07, type = rw, define = yes, optional = yes;
|
BANKRAM08: load = BRAM08, type = rw, optional = yes, define = yes;
|
||||||
BRAM08ADDR: load = BRAM08ADDR, type = ro, optional = yes;
|
BRAM09ADDR: load = BRAM09ADDR, type = ro, optional = yes;
|
||||||
BANKRAM08: load = BRAM08, type = rw, define = yes, optional = yes;
|
BANKRAM09: load = BRAM09, type = rw, optional = yes, define = yes;
|
||||||
BRAM09ADDR: load = BRAM09ADDR, type = ro, optional = yes;
|
BRAM0AADDR: load = BRAM0AADDR, type = ro, optional = yes;
|
||||||
BANKRAM09: load = BRAM09, type = rw, define = yes, optional = yes;
|
BANKRAM0A: load = BRAM0A, type = rw, optional = yes, define = yes;
|
||||||
BRAM0AADDR: load = BRAM0AADDR, type = ro, optional = yes;
|
BRAM0BADDR: load = BRAM0BADDR, type = ro, optional = yes;
|
||||||
BANKRAM0A: load = BRAM0A, type = rw, define = yes, optional = yes;
|
BANKRAM0B: load = BRAM0B, type = rw, optional = yes, define = yes;
|
||||||
BRAM0BADDR: load = BRAM0BADDR, type = ro, optional = yes;
|
BRAM0CADDR: load = BRAM0CADDR, type = ro, optional = yes;
|
||||||
BANKRAM0B: load = BRAM0B, type = rw, define = yes, optional = yes;
|
BANKRAM0C: load = BRAM0C, type = rw, optional = yes, define = yes;
|
||||||
BRAM0CADDR: load = BRAM0CADDR, type = ro, optional = yes;
|
BRAM0DADDR: load = BRAM0DADDR, type = ro, optional = yes;
|
||||||
BANKRAM0C: load = BRAM0C, type = rw, define = yes, optional = yes;
|
BANKRAM0D: load = BRAM0D, type = rw, optional = yes, define = yes;
|
||||||
BRAM0DADDR: load = BRAM0DADDR, type = ro, optional = yes;
|
BRAM0EADDR: load = BRAM0EADDR, type = ro, optional = yes;
|
||||||
BANKRAM0D: load = BRAM0D, type = rw, define = yes, optional = yes;
|
BANKRAM0E: load = BRAM0E, type = rw, optional = yes, define = yes;
|
||||||
BRAM0EADDR: load = BRAM0EADDR, type = ro, optional = yes;
|
BRAM0FADDR: load = BRAM0FADDR, type = ro, optional = yes;
|
||||||
BANKRAM0E: load = BRAM0E, type = rw, define = yes, optional = yes;
|
BANKRAM0F: load = BRAM0F, type = rw, optional = yes, define = yes;
|
||||||
BRAM0FADDR: load = BRAM0FADDR, type = ro, optional = yes;
|
|
||||||
BANKRAM0F: load = BRAM0F, type = rw, define = yes, optional = yes;
|
|
||||||
}
|
}
|
||||||
FEATURES {
|
FEATURES {
|
||||||
CONDES: type = constructor,
|
CONDES: type = constructor,
|
||||||
|
|||||||
12
cfg/cx16.cfg
12
cfg/cx16.cfg
@@ -16,17 +16,17 @@ MEMORY {
|
|||||||
}
|
}
|
||||||
SEGMENTS {
|
SEGMENTS {
|
||||||
ZEROPAGE: load = ZP, type = zp;
|
ZEROPAGE: load = ZP, type = zp;
|
||||||
EXTZP: load = ZP, type = zp, optional = yes;
|
EXTZP: load = ZP, type = zp, optional = yes;
|
||||||
LOADADDR: load = LOADADDR, type = ro;
|
LOADADDR: load = LOADADDR, type = ro;
|
||||||
EXEHDR: load = HEADER, type = ro;
|
EXEHDR: load = HEADER, type = ro;
|
||||||
STARTUP: load = MAIN, type = ro;
|
STARTUP: load = MAIN, type = ro, optional = yes;
|
||||||
LOWCODE: load = MAIN, type = ro, optional = yes;
|
LOWCODE: load = MAIN, type = ro, optional = yes;
|
||||||
CODE: load = MAIN, type = ro;
|
CODE: load = MAIN, type = ro;
|
||||||
RODATA: load = MAIN, type = ro;
|
RODATA: load = MAIN, type = ro;
|
||||||
DATA: load = MAIN, type = rw;
|
DATA: load = MAIN, type = rw;
|
||||||
INIT: load = MAIN, type = rw;
|
INIT: load = MAIN, type = rw, optional = yes;
|
||||||
ONCE: load = MAIN, type = ro, define = yes;
|
ONCE: load = MAIN, type = ro, define = yes;
|
||||||
BSS: load = BSS, type = bss, define = yes;
|
BSS: load = BSS, type = bss, define = yes;
|
||||||
}
|
}
|
||||||
FEATURES {
|
FEATURES {
|
||||||
CONDES: type = constructor,
|
CONDES: type = constructor,
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ information.
|
|||||||
|
|
||||||
<sect>Binary format<p>
|
<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
|
is a cartridge image. It is of course
|
||||||
possible to change this behaviour by using a modified startup file and linker
|
possible to change this behaviour by using a modified startup file and linker
|
||||||
config.
|
config.
|
||||||
@@ -219,10 +219,58 @@ you cannot use any of the following functions (and a few others):
|
|||||||
|
|
||||||
<sect>Other hints<p>
|
<sect>Other hints<p>
|
||||||
|
|
||||||
|
<sect1>CAR format<p>
|
||||||
|
|
||||||
AtariROMMaker (<url url="https://www.wudsn.com/index.php/productions-atari800/tools/atarirommaker"> )
|
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.
|
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.
|
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>
|
<sect>License<p>
|
||||||
|
|
||||||
|
|||||||
@@ -921,9 +921,8 @@ name="6502 binary relocation format specification">). It is defined like this:
|
|||||||
}
|
}
|
||||||
</verb></tscreen>
|
</verb></tscreen>
|
||||||
|
|
||||||
The other format available is the Atari (xex) segmented file format, this is
|
The other format available is the Atari segmented file format (xex), this is
|
||||||
the standard format used by Atari DOS 2.0 and upward file managers in the Atari
|
the standard format used by Atari DOS 2.0 and upwards, and it is defined like this:
|
||||||
8-bit computers, and it is defined like this:
|
|
||||||
|
|
||||||
<tscreen><verb>
|
<tscreen><verb>
|
||||||
FILES {
|
FILES {
|
||||||
@@ -1010,7 +1009,8 @@ The <tt/CONDES/ feature has several attributes:
|
|||||||
<tag><tt>segment</tt></tag>
|
<tag><tt>segment</tt></tag>
|
||||||
|
|
||||||
This attribute tells the linker into which segment the table should be
|
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>
|
<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
|
Without specifying the <tt/CONDES/ feature, the linker will not create any
|
||||||
tables, even if there are <tt/condes/ entries in the object files.
|
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">.
|
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
|
the compiler and the libraries that come with it. If you replace the builtin
|
||||||
config files, you will need the following information.
|
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>
|
<sect1>ONCE<p>
|
||||||
|
|
||||||
The ONCE segment is used for initialization code run only once before
|
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
|
may for example add the ONCE segment to the heap in really memory
|
||||||
constrained systems.
|
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>
|
<sect1>STARTUP<p>
|
||||||
|
|
||||||
This segment contains the startup code which initializes the C software stack
|
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> */
|
/* Freddy Offenga <taf_offenga@yahoo.com> */
|
||||||
/* Christian Groessler <chris@groessler.org> */
|
/* Christian Groessler <chris@groessler.org> */
|
||||||
/* Bill Kendrick <nbs@sonic.net> */
|
/* Bill Kendrick <nbs@sonic.net> */
|
||||||
|
/* et al. */
|
||||||
/* */
|
/* */
|
||||||
/* */
|
/* */
|
||||||
/* This software is provided 'as-is', without any expressed or implied */
|
/* This software is provided 'as-is', without any expressed or implied */
|
||||||
@@ -219,7 +220,7 @@
|
|||||||
/* Color register functions */
|
/* 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 void __fastcall__ _setcolor_low (unsigned char color_reg, unsigned char color_value);
|
||||||
extern unsigned char __fastcall__ _getcolor (unsigned char color_reg);
|
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);
|
unsigned char cbm_k_basin (void);
|
||||||
void __fastcall__ cbm_k_bsout (unsigned char C);
|
void __fastcall__ cbm_k_bsout (unsigned char C);
|
||||||
unsigned char __fastcall__ cbm_k_chkin (unsigned char FN);
|
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);
|
void __fastcall__ cbm_k_ciout (unsigned char C);
|
||||||
unsigned char __fastcall__ cbm_k_ckout (unsigned char FN);
|
unsigned char __fastcall__ cbm_k_ckout (unsigned char FN);
|
||||||
void cbm_k_clall (void);
|
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.
|
/* Reads one directory line into cbm_dirent structure.
|
||||||
** Returns 0 if reading directory-line was successful.
|
** Returns 0 if reading directory-line was successful.
|
||||||
** Returns non-zero if reading directory failed, or no more file-names to read.
|
** 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);
|
void __fastcall__ cbm_closedir (unsigned char lfn);
|
||||||
|
|||||||
@@ -133,8 +133,7 @@ MKINC = $(GEOS) \
|
|||||||
|
|
||||||
TARGETUTIL = apple2 \
|
TARGETUTIL = apple2 \
|
||||||
apple2enh \
|
apple2enh \
|
||||||
atari \
|
atari
|
||||||
geos-apple
|
|
||||||
|
|
||||||
GEOSDIRS = common \
|
GEOSDIRS = common \
|
||||||
conio \
|
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)
|
../libwrk/$(TARGET)/loader.o: $(SRCDIR)/targetutil/loader.s | ../libwrk/$(TARGET)
|
||||||
$(ASSEMBLE_recipe)
|
$(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
|
../target/$(TARGET)/util/loader.system: ../libwrk/$(TARGET)/loader.o $(SRCDIR)/targetutil/loader.cfg | ../target/$(TARGET)/util
|
||||||
$(LD65) -o $@ -C $(filter %.cfg,$^) $(filter-out %.cfg,$^)
|
$(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
|
; Ullrich von Bassewitz, 03.06.1999
|
||||||
;
|
;
|
||||||
; unsigned char cbm_k_basin (void);
|
; unsigned char cbm_k_basin (void);
|
||||||
|
; unsigned char cbm_k_chrin (void);
|
||||||
;
|
;
|
||||||
|
|
||||||
.include "cbm.inc"
|
.include "cbm.inc"
|
||||||
|
|
||||||
.export _cbm_k_basin
|
.export _cbm_k_basin, _cbm_k_chrin
|
||||||
|
|
||||||
|
|
||||||
_cbm_k_basin:
|
_cbm_k_basin:
|
||||||
|
_cbm_k_chrin:
|
||||||
jsr BASIN
|
jsr BASIN
|
||||||
ldx #0 ; Clear high byte
|
ldx #0 ; Clear high byte
|
||||||
rts
|
rts
|
||||||
|
|||||||
@@ -2,10 +2,12 @@
|
|||||||
; Ullrich von Bassewitz, 03.06.1999
|
; Ullrich von Bassewitz, 03.06.1999
|
||||||
;
|
;
|
||||||
; void __fastcall__ cbm_k_bsout (unsigned char C);
|
; void __fastcall__ cbm_k_bsout (unsigned char C);
|
||||||
|
; void __fastcall__ cbm_k_chrout (unsigned char C);
|
||||||
;
|
;
|
||||||
|
|
||||||
.include "cbm.inc"
|
.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 */
|
/* 2009-10-10 -- Version 0.3 */
|
||||||
/* 2011-04-07 -- Version 0.4, groepaz */
|
/* 2011-04-07 -- Version 0.4, groepaz */
|
||||||
/* 2011-04-14 -- Version 0.5, Greg King */
|
/* 2011-04-14 -- Version 0.5, Greg King */
|
||||||
|
/* 2021-02-15 -- Version 0.6, Greg King */
|
||||||
|
|
||||||
/* Tested with floppy-drive and IDE64 devices. */
|
/* Tested with floppy-drive and IDE64 devices. */
|
||||||
/* Not tested with messed (buggy) directory listings. */
|
/* Not tested with messed (buggy) directory listings. */
|
||||||
@@ -29,7 +30,7 @@ unsigned char cbm_opendir (unsigned char lfn, unsigned char device, ...)
|
|||||||
va_list ap;
|
va_list ap;
|
||||||
const char* name = "$";
|
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) {
|
if (__argsize__ == 4) {
|
||||||
va_start (ap, device);
|
va_start (ap, device);
|
||||||
name = va_arg (ap, const char*);
|
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();
|
byte = cbm_k_basin();
|
||||||
switch (byte) {
|
switch (byte) {
|
||||||
|
/* "B" BLOCKS FREE/USED. */
|
||||||
/* "B" BLOCKS FREE. */
|
/* "M" MB FREE. */
|
||||||
case 'b':
|
case 'b':
|
||||||
|
case 'm':
|
||||||
/* Read until end; careless callers might call us again. */
|
/* Read until end; careless callers might call us again. */
|
||||||
while (!cbm_k_readst()) {
|
while (!cbm_k_readst()) {
|
||||||
cbm_k_basin();
|
cbm_k_basin();
|
||||||
@@ -168,7 +170,6 @@ unsigned char __fastcall__ cbm_readdir (unsigned char lfn, register struct cbm_d
|
|||||||
}
|
}
|
||||||
|
|
||||||
rv = 0;
|
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 */
|
/* Bump the directory offset and include the bytes for line-link and size */
|
||||||
dir->off += count + 4;
|
dir->off += count + 4;
|
||||||
|
|
||||||
/* End of directory is reached if the buffer contains "blocks free". It is
|
/* End of directory is reached if the buffer contains "blocks free/used" or
|
||||||
** sufficient here to check for the leading 'b'. buffer will contain at
|
** "mb free.". It is sufficient here to check for the leading 'b' and 'm'.
|
||||||
** least one byte if we come here.
|
** buffer will contain at least one byte if we come here.
|
||||||
*/
|
*/
|
||||||
if (buffer[0] == 'b') {
|
switch (buffer[0]) {
|
||||||
goto exitpoint;
|
case 'b':
|
||||||
|
case 'm':
|
||||||
|
goto exitpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse the buffer for the filename and file type */
|
/* Parse the buffer for the filename and file type */
|
||||||
@@ -67,7 +71,6 @@ struct dirent* __fastcall__ readdir (register DIR* dir)
|
|||||||
b = buffer;
|
b = buffer;
|
||||||
while (i < count) {
|
while (i < count) {
|
||||||
switch (s) {
|
switch (s) {
|
||||||
|
|
||||||
case 0:
|
case 0:
|
||||||
/* Searching for start of file name */
|
/* Searching for start of file name */
|
||||||
if (*b == '"') {
|
if (*b == '"') {
|
||||||
@@ -127,6 +130,3 @@ struct dirent* __fastcall__ readdir (register DIR* dir)
|
|||||||
exitpoint:
|
exitpoint:
|
||||||
return 0;
|
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
|
||||||
@@ -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
|
/* Negate the result as long as val < 0, even if val == -1 and no
|
||||||
** shift was generated. */
|
** shift was generated.
|
||||||
|
*/
|
||||||
if (Negation) {
|
if (Negation) {
|
||||||
g_neg (flags);
|
g_neg (flags);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -493,22 +493,28 @@ fncls_t GetFuncInfo (const char* Name, unsigned int* Use, unsigned int* Chg)
|
|||||||
** registers.
|
** registers.
|
||||||
*/
|
*/
|
||||||
*Use = REG_EAXY;
|
*Use = REG_EAXY;
|
||||||
} else if (D->ParamCount > 0 &&
|
} else if ((D->ParamCount > 0 ||
|
||||||
|
(D->Flags & FD_EMPTY) != 0) &&
|
||||||
(AutoCDecl ?
|
(AutoCDecl ?
|
||||||
IsQualFastcall (E->Type) :
|
IsQualFastcall (E->Type) :
|
||||||
!IsQualCDecl (E->Type))) {
|
!IsQualCDecl (E->Type))) {
|
||||||
/* Will use registers depending on the last param. If the last
|
/* 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)) {
|
if (D->LastParam != 0) {
|
||||||
case 1u:
|
switch (SizeOf(D->LastParam->Type)) {
|
||||||
*Use = REG_A;
|
case 1u:
|
||||||
break;
|
*Use = REG_A;
|
||||||
case 2u:
|
break;
|
||||||
*Use = REG_AX;
|
case 2u:
|
||||||
break;
|
*Use = REG_AX;
|
||||||
default:
|
break;
|
||||||
*Use = REG_EAX;
|
default:
|
||||||
|
*Use = REG_EAX;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
*Use = REG_EAX;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Will not use any registers */
|
/* Will not use any registers */
|
||||||
|
|||||||
@@ -356,8 +356,9 @@ static int Affected (LoadRegInfo* LRI, const CodeEntry* E)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((LRI->Flags & LI_CHECK_Y) != 0) {
|
if ((LRI->Flags & LI_CHECK_Y) != 0) {
|
||||||
/* If we don't know what memory location could have been used by Y,
|
/* If we don't know what memory location could have been
|
||||||
** we just assume all. */
|
** used by Y, we just assume all.
|
||||||
|
*/
|
||||||
if (YE == 0 ||
|
if (YE == 0 ||
|
||||||
(YE->ArgOff == E->ArgOff && strcmp (YE->ArgBase, E->ArgBase) == 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 */
|
/* Otherwise unaffected */
|
||||||
goto L_Result;
|
goto L_Result;
|
||||||
}
|
}
|
||||||
/* We could've check further for more cases where the load target isn't
|
/* We could've check further for more cases where the load target
|
||||||
** modified, but for now let's save the trouble and just play it safe.
|
** isn't modified, but for now let's save the trouble and just play
|
||||||
|
** it safe.
|
||||||
*/
|
*/
|
||||||
goto L_Affected;
|
goto L_Affected;
|
||||||
}
|
}
|
||||||
@@ -1080,7 +1082,7 @@ void AddOpHigh (StackOpData* D, opc_t OPC, LoadInfo* LI, int KeepResult)
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if ((LI->A.Flags & LI_CHECK_Y) == 0) {
|
if ((LI->X.Flags & LI_CHECK_Y) == 0) {
|
||||||
/* ldy #const */
|
/* ldy #const */
|
||||||
X = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (LI->X.Offs), 0, D->OpEntry->LI);
|
X = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (LI->X.Offs), 0, D->OpEntry->LI);
|
||||||
} else {
|
} 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);
|
X = NewCodeEntry (OPC, AM65_ZP_INDY, "sp", 0, D->OpEntry->LI);
|
||||||
} else {
|
} else {
|
||||||
/* opc src,y */
|
/* 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++);
|
InsertEntry (D, X, D->IP++);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1500,14 +1500,11 @@ unsigned OptShiftBack (CodeSeg* S)
|
|||||||
(N->OPC == OP65_LSR ||
|
(N->OPC == OP65_LSR ||
|
||||||
N->OPC == OP65_ROR) &&
|
N->OPC == OP65_ROR) &&
|
||||||
!CE_HasLabel (N)) {
|
!CE_HasLabel (N)) {
|
||||||
|
|
||||||
CheckStates = PSTATE_ZN;
|
CheckStates = PSTATE_ZN;
|
||||||
|
|
||||||
if (N->OPC == OP65_LSR &&
|
if (N->OPC == OP65_LSR &&
|
||||||
!PStatesAreClear (E->RI->Out.PFlags, PSTATE_C)) {
|
!PStatesAreClear (E->RI->Out.PFlags, PSTATE_C)) {
|
||||||
CheckStates |= REG_A;
|
CheckStates |= REG_A;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((GetRegInfo (S, I+2, CheckStates) & CheckStates) == 0) {
|
if ((GetRegInfo (S, I+2, CheckStates) & CheckStates) == 0) {
|
||||||
|
|
||||||
/* Remove the shifts */
|
/* Remove the shifts */
|
||||||
|
|||||||
@@ -453,6 +453,7 @@ static unsigned Opt_staxspidx (StackOpData* D)
|
|||||||
/* Optimize the staxspidx sequence */
|
/* Optimize the staxspidx sequence */
|
||||||
{
|
{
|
||||||
CodeEntry* X;
|
CodeEntry* X;
|
||||||
|
const char* Arg = 0;
|
||||||
|
|
||||||
/* Check if we're using a register variable */
|
/* Check if we're using a register variable */
|
||||||
if (!IsRegVar (D)) {
|
if (!IsRegVar (D)) {
|
||||||
@@ -469,7 +470,7 @@ static unsigned Opt_staxspidx (StackOpData* D)
|
|||||||
|
|
||||||
if (RegValIsKnown (D->OpEntry->RI->In.RegY)) {
|
if (RegValIsKnown (D->OpEntry->RI->In.RegY)) {
|
||||||
/* Value of Y is known */
|
/* 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);
|
X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, D->OpEntry->LI);
|
||||||
} else {
|
} else {
|
||||||
X = NewCodeEntry (OP65_INY, AM65_IMP, 0, 0, D->OpEntry->LI);
|
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)) {
|
if (RegValIsKnown (D->OpEntry->RI->In.RegX)) {
|
||||||
/* Value of X is known */
|
/* 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);
|
X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, D->OpEntry->LI);
|
||||||
} else {
|
} else {
|
||||||
/* Value unknown */
|
/* 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
|
/* If we remove staxspidx, we must restore the Y register to what the
|
||||||
** function would return.
|
** 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);
|
InsertEntry (D, X, D->OpIndex+5);
|
||||||
|
|
||||||
/* Remove the push and the call to the staxspidx function */
|
/* 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 */
|
Type* T = TypeAlloc (3); /* func/returns int/terminator */
|
||||||
|
|
||||||
/* Prepare the function descriptor */
|
/* Prepare the function descriptor */
|
||||||
F->Flags = FD_EMPTY | FD_VARIADIC;
|
F->Flags = FD_EMPTY;
|
||||||
F->SymTab = &EmptySymTab;
|
F->SymTab = &EmptySymTab;
|
||||||
F->TagTab = &EmptySymTab;
|
F->TagTab = &EmptySymTab;
|
||||||
|
|
||||||
@@ -755,8 +755,9 @@ unsigned SizeOf (const Type* T)
|
|||||||
return T->A.U;
|
return T->A.U;
|
||||||
|
|
||||||
/* Beware: There's a chance that this triggers problems in other parts
|
/* Beware: There's a chance that this triggers problems in other parts
|
||||||
of the compiler. The solution is to fix the callers, because calling
|
** of the compiler. The solution is to fix the callers, because calling
|
||||||
SizeOf() with a function type as argument is bad. */
|
** SizeOf() with a function type as argument is bad.
|
||||||
|
*/
|
||||||
case T_FUNC:
|
case T_FUNC:
|
||||||
return 0; /* Size of function is unknown */
|
return 0; /* Size of function is unknown */
|
||||||
|
|
||||||
|
|||||||
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)
|
static const GenDesc* FindGen (token_t Tok, const GenDesc* Table)
|
||||||
/* Find a token in a generator table */
|
/* Find a token in a generator table */
|
||||||
{
|
{
|
||||||
@@ -376,6 +412,9 @@ void DoneDeferredOps (void)
|
|||||||
static void DeferInc (const ExprDesc* Expr)
|
static void DeferInc (const ExprDesc* Expr)
|
||||||
/* Defer the post-inc and put it in a queue */
|
/* Defer the post-inc and put it in a queue */
|
||||||
{
|
{
|
||||||
|
if (ED_IsUneval (Expr)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
DeferredOp* Op = xmalloc (sizeof (DeferredOp));
|
DeferredOp* Op = xmalloc (sizeof (DeferredOp));
|
||||||
memcpy (&Op->Expr, Expr, sizeof (ExprDesc));
|
memcpy (&Op->Expr, Expr, sizeof (ExprDesc));
|
||||||
Op->OpType = DOT_INC;
|
Op->OpType = DOT_INC;
|
||||||
@@ -387,6 +426,9 @@ static void DeferInc (const ExprDesc* Expr)
|
|||||||
static void DeferDec (const ExprDesc* Expr)
|
static void DeferDec (const ExprDesc* Expr)
|
||||||
/* Defer the post-dec and put it in a queue */
|
/* Defer the post-dec and put it in a queue */
|
||||||
{
|
{
|
||||||
|
if (ED_IsUneval (Expr)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
DeferredOp* Op = xmalloc (sizeof (DeferredOp));
|
DeferredOp* Op = xmalloc (sizeof (DeferredOp));
|
||||||
memcpy (&Op->Expr, Expr, sizeof (ExprDesc));
|
memcpy (&Op->Expr, Expr, sizeof (ExprDesc));
|
||||||
Op->OpType = DOT_DEC;
|
Op->OpType = DOT_DEC;
|
||||||
@@ -1171,16 +1213,16 @@ static void Primary (ExprDesc* E)
|
|||||||
|
|
||||||
/* IDENT is either an auto-declared function or an undefined variable. */
|
/* IDENT is either an auto-declared function or an undefined variable. */
|
||||||
if (CurTok.Tok == TOK_LPAREN) {
|
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
|
** generate an error and otherwise a warning. Declare a
|
||||||
** function returning int. For that purpose, prepare a
|
** function returning int. For that purpose, prepare a
|
||||||
** function signature for a function having an empty param
|
** function signature for a function having an empty param
|
||||||
** list and returning int.
|
** list and returning int.
|
||||||
*/
|
*/
|
||||||
if (IS_Get (&Standard) >= STD_C99) {
|
if (IS_Get (&Standard) >= STD_C99) {
|
||||||
Error ("Call to undefined function '%s'", Ident);
|
Error ("Call to undeclared function '%s'", Ident);
|
||||||
} else {
|
} 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);
|
Sym = AddGlobalSym (Ident, GetImplicitFuncType(), SC_EXTERN | SC_REF | SC_FUNC);
|
||||||
E->Type = Sym->Type;
|
E->Type = Sym->Type;
|
||||||
@@ -2159,15 +2201,19 @@ static void UnaryOp (ExprDesc* Expr)
|
|||||||
ED_MakeConstAbsInt (Expr, 1);
|
ED_MakeConstAbsInt (Expr, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for a constant expression */
|
/* Check for a constant numeric expression */
|
||||||
if (ED_IsConstAbs (Expr)) {
|
if (ED_IsConstAbs (Expr)) {
|
||||||
/* Value is constant */
|
/* Value is numeric */
|
||||||
switch (Tok) {
|
switch (Tok) {
|
||||||
case TOK_MINUS: Expr->IVal = -Expr->IVal; break;
|
case TOK_MINUS: Expr->IVal = -Expr->IVal; break;
|
||||||
case TOK_PLUS: break;
|
case TOK_PLUS: break;
|
||||||
case TOK_COMP: Expr->IVal = ~Expr->IVal; break;
|
case TOK_COMP: Expr->IVal = ~Expr->IVal; break;
|
||||||
default: Internal ("Unexpected token: %d", Tok);
|
default: Internal ("Unexpected token: %d", Tok);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Limit the calculated value to the range of its type */
|
||||||
|
LimitExprValue (Expr);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
/* Value is not constant */
|
/* Value is not constant */
|
||||||
LoadExpr (CF_NONE, Expr);
|
LoadExpr (CF_NONE, Expr);
|
||||||
@@ -2218,7 +2264,7 @@ void hie10 (ExprDesc* Expr)
|
|||||||
NextToken ();
|
NextToken ();
|
||||||
BoolExpr (hie10, Expr);
|
BoolExpr (hie10, Expr);
|
||||||
if (ED_IsConstAbs (Expr)) {
|
if (ED_IsConstAbs (Expr)) {
|
||||||
/* Constant expression */
|
/* Constant numeric expression */
|
||||||
Expr->IVal = !Expr->IVal;
|
Expr->IVal = !Expr->IVal;
|
||||||
} else if (ED_IsAddrExpr (Expr)) {
|
} else if (ED_IsAddrExpr (Expr)) {
|
||||||
/* Address != NULL, so !Address == 0 */
|
/* 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) {
|
} else if (lconst && (Gen->Flags & GEN_COMM) && !rconst) {
|
||||||
/* If the LHS constant is an int that fits into an unsigned char, change the
|
/* 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
|
** 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
|
/* If the result is constant, this is suspicious when not in
|
||||||
** preprocessor mode.
|
** preprocessor mode.
|
||||||
*/
|
*/
|
||||||
@@ -2796,7 +2848,7 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Determine the type of the operation. */
|
/* 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.
|
/* Left side is unsigned char, right side is constant.
|
||||||
** Determine the minimum and maximum values
|
** Determine the minimum and maximum values
|
||||||
@@ -2809,20 +2861,6 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */
|
|||||||
LeftMin = 0;
|
LeftMin = 0;
|
||||||
LeftMax = 255;
|
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
|
/* Comparing a char against a constant may have a constant
|
||||||
** result. Please note: It is not possible to remove the code
|
** 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.
|
** since the right side constant is in a valid range.
|
||||||
*/
|
*/
|
||||||
flags |= (CF_CHAR | CF_FORCECHAR);
|
flags |= (CF_CHAR | CF_FORCECHAR);
|
||||||
if (!LeftSigned) {
|
if (!LeftSigned || !RightSigned) {
|
||||||
flags |= CF_UNSIGNED;
|
flags |= CF_UNSIGNED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2902,7 +2940,7 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */
|
|||||||
if (rconst) {
|
if (rconst) {
|
||||||
flags |= CF_FORCECHAR;
|
flags |= CF_FORCECHAR;
|
||||||
}
|
}
|
||||||
if (!LeftSigned) {
|
if (!LeftSigned || !RightSigned) {
|
||||||
flags |= CF_UNSIGNED;
|
flags |= CF_UNSIGNED;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -2910,11 +2948,11 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */
|
|||||||
flags |= g_typeadjust (ltype, rtype);
|
flags |= g_typeadjust (ltype, rtype);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the left side is an unsigned and the right is a constant,
|
/* If the comparison is made as unsigned types and the right is a
|
||||||
** we may be able to change the compares to something more
|
** constant, we may be able to change the compares to something more
|
||||||
** effective.
|
** effective.
|
||||||
*/
|
*/
|
||||||
if (!LeftSigned && rconst) {
|
if ((!LeftSigned || !RightSigned) && rconst) {
|
||||||
|
|
||||||
switch (Tok) {
|
switch (Tok) {
|
||||||
|
|
||||||
@@ -3042,6 +3080,9 @@ static void parseadd (ExprDesc* Expr)
|
|||||||
/* Integer addition */
|
/* Integer addition */
|
||||||
Expr->IVal += Expr2.IVal;
|
Expr->IVal += Expr2.IVal;
|
||||||
typeadjust (Expr, &Expr2, 1);
|
typeadjust (Expr, &Expr2, 1);
|
||||||
|
|
||||||
|
/* Limit the calculated value to the range of its type */
|
||||||
|
LimitExprValue (Expr);
|
||||||
} else {
|
} else {
|
||||||
/* OOPS */
|
/* OOPS */
|
||||||
Error ("Invalid operands for binary operator '+'");
|
Error ("Invalid operands for binary operator '+'");
|
||||||
@@ -3130,6 +3171,9 @@ static void parseadd (ExprDesc* Expr)
|
|||||||
flags = CF_INT;
|
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 */
|
/* Result is an rvalue in primary register */
|
||||||
ED_FinalizeRValLoad (Expr);
|
ED_FinalizeRValLoad (Expr);
|
||||||
}
|
}
|
||||||
@@ -3225,7 +3269,7 @@ static void parseadd (ExprDesc* Expr)
|
|||||||
ED_FinalizeRValLoad (Expr);
|
ED_FinalizeRValLoad (Expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Condition codes not set */
|
/* Condition code not set */
|
||||||
ED_MarkAsUntested (Expr);
|
ED_MarkAsUntested (Expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3301,7 +3345,7 @@ static void parsesub (ExprDesc* Expr)
|
|||||||
Error ("Incompatible pointer types");
|
Error ("Incompatible pointer types");
|
||||||
} else {
|
} else {
|
||||||
Expr->IVal = (Expr->IVal - Expr2.IVal) /
|
Expr->IVal = (Expr->IVal - Expr2.IVal) /
|
||||||
CheckedPSizeOf (lhst);
|
(long)CheckedPSizeOf (lhst);
|
||||||
}
|
}
|
||||||
/* Operate on pointers, result type is an integer */
|
/* Operate on pointers, result type is an integer */
|
||||||
Expr->Type = type_int;
|
Expr->Type = type_int;
|
||||||
@@ -3309,14 +3353,14 @@ static void parsesub (ExprDesc* Expr)
|
|||||||
/* Integer subtraction */
|
/* Integer subtraction */
|
||||||
typeadjust (Expr, &Expr2, 1);
|
typeadjust (Expr, &Expr2, 1);
|
||||||
Expr->IVal -= Expr2.IVal;
|
Expr->IVal -= Expr2.IVal;
|
||||||
|
|
||||||
|
/* Limit the calculated value to the range of its type */
|
||||||
|
LimitExprValue (Expr);
|
||||||
} else {
|
} else {
|
||||||
/* OOPS */
|
/* OOPS */
|
||||||
Error ("Invalid operands for binary operator '-'");
|
Error ("Invalid operands for binary operator '-'");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Result is constant, condition codes not set */
|
|
||||||
ED_MarkAsUntested (Expr);
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
/* Left hand side is not constant, right hand side is.
|
/* 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 */
|
/* Result is an rvalue in the primary register */
|
||||||
ED_FinalizeRValLoad (Expr);
|
ED_FinalizeRValLoad (Expr);
|
||||||
ED_MarkAsUntested (Expr);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@@ -3412,8 +3454,10 @@ static void parsesub (ExprDesc* Expr)
|
|||||||
|
|
||||||
/* Result is an rvalue in the primary register */
|
/* Result is an rvalue in the primary register */
|
||||||
ED_FinalizeRValLoad (Expr);
|
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->Sym = 0;
|
||||||
Expr->Type = type_bool;
|
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->Name = 0;
|
||||||
Expr->IVal = Value;
|
Expr->IVal = Value;
|
||||||
Expr->FVal = FP_D_Make (0.0);
|
Expr->FVal = FP_D_Make (0.0);
|
||||||
|
|||||||
@@ -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)
|
SymEntry* AddGlobalSym (const char* Name, const Type* T, unsigned Flags)
|
||||||
/* Add an external or global symbol to the symbol table and return the entry */
|
/* 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;
|
SymTable* Tab = SymTab;
|
||||||
|
|
||||||
/* Do we have an entry with this name already? */
|
/* Do we have an entry with this name already? */
|
||||||
SymEntry* Entry = FindSymInTree (Tab, Name);
|
SymEntry* Entry = FindSymInTree (Tab, Name);
|
||||||
if (Entry) {
|
if (Entry) {
|
||||||
|
|
||||||
/* We have a symbol with this name already */
|
/* We have a symbol with this name already */
|
||||||
if (HandleSymRedefinition (Entry, T, Flags)) {
|
if (HandleSymRedefinition (Entry, T, Flags)) {
|
||||||
Entry = 0;
|
Entry = 0;
|
||||||
@@ -1215,8 +1216,11 @@ SymEntry* AddGlobalSym (const char* Name, const Type* T, unsigned Flags)
|
|||||||
/* Use the fail-safe table for fictitious symbols */
|
/* Use the fail-safe table for fictitious symbols */
|
||||||
Tab = FailSafeTab;
|
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) {
|
if (Entry == 0 || Entry->Owner != Tab) {
|
||||||
|
|
||||||
/* Create a new entry */
|
/* Create a new entry */
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ unsigned Test (unsigned Label, int Invert)
|
|||||||
/* Read a boolean expression */
|
/* Read a boolean expression */
|
||||||
BoolExpr (hie0, &Expr);
|
BoolExpr (hie0, &Expr);
|
||||||
|
|
||||||
/* Check for a constant expression */
|
/* Check for a constant numeric expression */
|
||||||
if (ED_IsConstAbs (&Expr)) {
|
if (ED_IsConstAbs (&Expr)) {
|
||||||
|
|
||||||
/* Append deferred inc/dec at sequence point */
|
/* Append deferred inc/dec at sequence point */
|
||||||
|
|||||||
@@ -101,13 +101,12 @@ $(WORKDIR)/bug1263.$1.$2.prg: bug1263.c | $(WORKDIR)
|
|||||||
$(NOT) $(CC65) -t sim$2 -$1 -o $$@ $$< $(NULLERR)
|
$(NOT) $(CC65) -t sim$2 -$1 -o $$@ $$< $(NULLERR)
|
||||||
|
|
||||||
# this one requires --std=c89, it fails with --std=c99
|
# this one requires --std=c89, it fails with --std=c99
|
||||||
# it fails currently at runtime
|
|
||||||
$(WORKDIR)/bug1265.$1.$2.prg: bug1265.c | $(WORKDIR)
|
$(WORKDIR)/bug1265.$1.$2.prg: bug1265.c | $(WORKDIR)
|
||||||
$(if $(QUIET),echo misc/bug1265.$1.$2.prg)
|
$(if $(QUIET),echo misc/bug1265.$1.$2.prg)
|
||||||
$(CC65) --standard c89 -t sim$2 -$1 -o $$(@:.prg=.s) $$< $(NULLERR)
|
$(CC65) --standard c89 -t sim$2 -$1 -o $$(@:.prg=.s) $$< $(NULLERR)
|
||||||
$(CA65) -t sim$2 -o $$(@:.prg=.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)
|
$(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
|
# should compile, but then hangs in an endless loop
|
||||||
$(WORKDIR)/endless.$1.$2.prg: endless.c | $(WORKDIR)
|
$(WORKDIR)/endless.$1.$2.prg: endless.c | $(WORKDIR)
|
||||||
|
|||||||
@@ -14,11 +14,9 @@ int main (void) {
|
|||||||
int x, n;
|
int x, n;
|
||||||
|
|
||||||
sprintf (str1, "%p\n", &x);
|
sprintf (str1, "%p\n", &x);
|
||||||
puts(str1);
|
|
||||||
x = 1234;
|
x = 1234;
|
||||||
n = f1 (x);
|
n = f1 (x);
|
||||||
sprintf (str2, "%p\n", &x);
|
sprintf (str2, "%p\n", &x);
|
||||||
puts(str2);
|
|
||||||
|
|
||||||
if (strcmp(str1, str2)) {
|
if (strcmp(str1, str2)) {
|
||||||
puts("not equal");
|
puts("not equal");
|
||||||
@@ -30,11 +28,9 @@ int main (void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sprintf (str1, "%p\n", &x);
|
sprintf (str1, "%p\n", &x);
|
||||||
puts(str1);
|
|
||||||
x = 2345;
|
x = 2345;
|
||||||
n = f2 (x);
|
n = f2 (x);
|
||||||
sprintf (str2, "%p\n", &x);
|
sprintf (str2, "%p\n", &x);
|
||||||
puts(str2);
|
|
||||||
|
|
||||||
if (strcmp(str1, str2)) {
|
if (strcmp(str1, str2)) {
|
||||||
puts("not equal");
|
puts("not equal");
|
||||||
|
|||||||
@@ -68,6 +68,20 @@ int main (void)
|
|||||||
failures++;
|
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);
|
printf ("failures: %u\n", failures);
|
||||||
|
|
||||||
return 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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user