mirror of
https://github.com/cc65/cc65.git
synced 2024-06-15 02:29:32 +00:00
commit
0636c4bc30
|
@ -15,6 +15,7 @@ PROMPT := $33 ; Used by GETLN
|
|||
RNDL := $4E ; Random counter low
|
||||
RNDH := $4F ; Random counter high
|
||||
HIMEM := $73 ; Highest available memory address+1
|
||||
CURLIN := $75 ; Current line number being executed
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; Vectors
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
; Zero page, Commodore stuff
|
||||
|
||||
TXTPTR := $3D ; Pointer into BASIC source code
|
||||
STATUS := $90 ; Kernal I/O completion status
|
||||
TIME := $A0 ; 60HZ clock
|
||||
FNAM_LEN := $B7 ; Length of filename
|
||||
SECADR := $B9 ; Secondary address
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
VARTAB := $2D ; Pointer to start of BASIC variables
|
||||
MEMSIZE := $37 ; Pointer to highest BASIC RAM location (+1)
|
||||
TXTPTR := $7A ; Pointer into BASIC source code
|
||||
STATUS := $90 ; Kernal I/O completion status
|
||||
TIME := $A0 ; 60 HZ clock
|
||||
FNAM_LEN := $B7 ; Length of filename
|
||||
SECADR := $B9 ; Secondary address
|
||||
|
|
|
@ -10,6 +10,7 @@ TMPPTR := $22 ; Temporary ptr used by BASIC
|
|||
VARTAB := $2D ; Pointer to start of BASIC variables
|
||||
MEMSIZE := $37 ; Pointer to highest BASIC RAM location (+1)
|
||||
TXTPTR := $3B ; Pointer into BASIC source code
|
||||
STATUS := $90 ; Kernal I/O completion status
|
||||
TIME := $A3 ; 60HZ clock
|
||||
FNAM_LEN := $AB ; Length of filename
|
||||
LFN := $AC ; Logical file number
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
VARTAB := $2D ; Pointer to start of BASIC variables
|
||||
MEMSIZE := $37 ; Pointer to highest BASIC RAM location (+1)
|
||||
TXTPTR := $7A ; Pointer into BASIC source code
|
||||
STATUS := $90 ; Kernal I/O completion status
|
||||
TIME := $A0 ; 60HZ clock
|
||||
FNAM_LEN := $B7 ; Length of filename
|
||||
SECADR := $B9 ; Secondary address
|
||||
|
|
|
@ -73,7 +73,18 @@ Special locations:
|
|||
|
||||
Programs containing Atari 5200 specific code may use the <tt/atari5200.h/ header file.
|
||||
|
||||
This also includes access to operating system locations (e.g. hardware shadow registers) by a structure called
|
||||
"<tt/OS/".
|
||||
The names are the usual ones you can find in system reference manuals. Example:
|
||||
|
||||
<tscreen><verb>
|
||||
...
|
||||
OS.sdmctl = 0x00; // screen off
|
||||
OS.color4 = 14; // white frame
|
||||
tics = OS.rtclok[1] // get ticks
|
||||
...
|
||||
</verb></tscreen>
|
||||
|
||||
<sect1>Atari 5200 specific functions<p>
|
||||
|
||||
<itemize>
|
||||
|
|
158
doc/cc65.sgml
158
doc/cc65.sgml
|
@ -6,8 +6,9 @@
|
|||
<url url="mailto:gregdk@users.sf.net" name="Greg King">
|
||||
|
||||
<abstract>
|
||||
cc65 is a C compiler for 6502 targets. It supports several 6502 based home
|
||||
computers like the Commodore and Atari machines, but it is easily retargetable.
|
||||
cc65 is a C compiler for 6502 targets. It supports several 6502-based home
|
||||
computers such as the Commodore and Atari machines, but it easily is
|
||||
retargetable.
|
||||
</abstract>
|
||||
|
||||
<!-- Table of contents -->
|
||||
|
@ -548,6 +549,8 @@ Here is a description of all the command line options:
|
|||
<tag><tt/remap-zero/</tag>
|
||||
Warn about a <tt/<ref id="pragma-charmap" name="#pragma charmap()">/
|
||||
that changes a character's code number from/to 0x00.
|
||||
<tag><tt/return-type/</tag>
|
||||
Warn about no return statement in function returning non-void.
|
||||
<tag><tt/struct-param/</tag>
|
||||
Warn when passing structs by value.
|
||||
<tag><tt/unknown-pragma/</tag>
|
||||
|
@ -706,12 +709,13 @@ This cc65 version has some extensions to the ISO C standard.
|
|||
places.
|
||||
<p>
|
||||
|
||||
<item> There are two pseudo variables named <tt/__AX__/ and <tt/__EAX__/.
|
||||
Both refer to the primary register that is used by the compiler to
|
||||
evaluate expressions or return function results. <tt/__AX__/ is of
|
||||
type <tt/unsigned int/ and <tt/__EAX__/ of type <tt/long unsigned int/
|
||||
respectively. The pseudo variables may be used as lvalue and rvalue as
|
||||
every other variable. They are most useful together with short
|
||||
<item> There are three pseudo variables named <tt/__A__/, <tt/__AX__/ and
|
||||
<tt/__EAX__/. They all refer to the primary register that is used
|
||||
by the compiler to evaluate expressions or return function results.
|
||||
<tt/__A__/ is of type <tt/unsigned char/, <tt/__AX__/ is of type
|
||||
<tt/unsigned int/ and <tt/__EAX__/ of type <tt/long unsigned int/
|
||||
respectively. The pseudo variables may be used as lvalue and rvalue
|
||||
as every other variable. They are most useful together with short
|
||||
sequences of assembler code. For example, the macro
|
||||
|
||||
<tscreen><verb>
|
||||
|
@ -1011,7 +1015,7 @@ The compiler defines several macros at startup:
|
|||
<tag><tt>__TELESTRAT__</tt></tag>
|
||||
|
||||
This macro is defined if the target is the Telestrat (-t telestrat).
|
||||
|
||||
|
||||
<tag><tt>__TIME__</tt></tag>
|
||||
|
||||
This macro expands to the time of translation of the preprocessing
|
||||
|
@ -1045,26 +1049,39 @@ parameter with the <tt/#pragma/.
|
|||
The <tt/#pragma/ understands the push and pop parameters as explained above.
|
||||
|
||||
|
||||
<sect1><tt>#pragma bss-name ([push,] <name>)</tt><label id="pragma-bss-name"><p>
|
||||
<sect1><tt>#pragma bss-name ([push, ]<name>[ ,<addrsize>])</tt><label id="pragma-bss-name"><p>
|
||||
|
||||
This pragma changes the name used for the BSS segment (the BSS segment
|
||||
is used to store variables with static storage duration and no explicit
|
||||
initializer). The argument is a string enclosed in double quotes.
|
||||
This pragma changes the name used for the BSS segment (the BSS segment is
|
||||
used to store variables with static storage duration and no explicit
|
||||
initializers). The <tt/name/ argument is a string enclosed in quotation
|
||||
marks.
|
||||
|
||||
Note: The default linker configuration file does only map the standard
|
||||
segments. If you use other segments, you have to create a new linker
|
||||
configuration file.
|
||||
<tt/addrsize/ is an optional string that gives a hint about where the
|
||||
<tt/name/ segment will be put in the CPU's address space. It describes the
|
||||
width of address numbers that point into that segment. Only words that
|
||||
are known to ca65 are allowed:
|
||||
<enum>
|
||||
<item>"zp", "zeropage", "direct"
|
||||
<item>"abs", "absolute", "near", "default"
|
||||
<item>"far"
|
||||
<item>"long", "dword"
|
||||
</enum>
|
||||
|
||||
Beware: The startup code will zero only the default BSS segment. If you
|
||||
use another BSS segment, you have to do that yourself, otherwise
|
||||
variables with static storage duration and no explicit initializer will
|
||||
not have the value zero.
|
||||
Note: The default linker configuration file maps only the standard segments.
|
||||
If you use other segments, you must create a new linker configuration file.
|
||||
|
||||
The <tt/#pragma/ understands the push and pop parameters as explained above.
|
||||
Beware: The start-up code will zero only the default BSS segment. If you use
|
||||
another BSS segment, then you must do that yourself; otherwise, variables
|
||||
with static storage duration and no explicit initializer will not have the
|
||||
value zero.
|
||||
|
||||
Example:
|
||||
The <tt/#pragma/ understands the push and pop parameters, as explained above.
|
||||
|
||||
Examples:
|
||||
<tscreen><verb>
|
||||
#pragma bss-name ("MyBSS")
|
||||
#pragma bss-name ("MyBSS")
|
||||
#pragma bss-name (push, "MyBSS")
|
||||
#pragma bss-name ("MyBSS", "zp")
|
||||
</verb></tscreen>
|
||||
|
||||
|
||||
|
@ -1120,21 +1137,33 @@ parameter with the <tt/#pragma/.
|
|||
The <tt/#pragma/ understands the push and pop parameters as explained above.
|
||||
|
||||
|
||||
<sect1><tt>#pragma code-name ([push,] <name>)</tt><label id="pragma-code-name"><p>
|
||||
<sect1><tt>#pragma code-name ([push, ]<name>[ ,<addrsize>])</tt><label id="pragma-code-name"><p>
|
||||
|
||||
This pragma changes the name used for the CODE segment (the CODE segment
|
||||
is used to store executable code). The argument is a string enclosed in
|
||||
double quotes.
|
||||
This pragma changes the name used for the CODE segment (the CODE segment is
|
||||
used to store executable code). The <tt/name/ argument is a string enclosed
|
||||
in quotation marks.
|
||||
|
||||
Note: The default linker configuration file does only map the standard
|
||||
segments. If you use other segments, you have to create a new linker
|
||||
configuration file.
|
||||
<tt/addrsize/ is an optional string that gives a hint about where the
|
||||
<tt/name/ segment will be put in the CPU's address space. It describes the
|
||||
width of address numbers that point into that segment. Only words that
|
||||
are known to ca65 are allowed:
|
||||
<enum>
|
||||
<item>"zp", "zeropage", "direct"
|
||||
<item>"abs", "absolute", "near", "default"
|
||||
<item>"far"
|
||||
<item>"long", "dword"
|
||||
</enum>
|
||||
|
||||
The <tt/#pragma/ understands the push and pop parameters as explained above.
|
||||
Note: The default linker configuration file maps only the standard segments.
|
||||
If you use other segments, you must create a new linker configuration file.
|
||||
|
||||
Example:
|
||||
The <tt/#pragma/ understands the push and pop parameters, as explained above.
|
||||
|
||||
Examples:
|
||||
<tscreen><verb>
|
||||
#pragma code-name ("MyCODE")
|
||||
#pragma code-name ("MyCODE")
|
||||
#pragma code-name (push, "MyCODE")
|
||||
#pragma code-name (push, "MyCODE", "far")
|
||||
</verb></tscreen>
|
||||
|
||||
|
||||
|
@ -1148,21 +1177,33 @@ parameter with the <tt/#pragma/.
|
|||
The <tt/#pragma/ understands the push and pop parameters as explained above.
|
||||
|
||||
|
||||
<sect1><tt>#pragma data-name ([push,] <name>)</tt><label id="pragma-data-name"><p>
|
||||
<sect1><tt>#pragma data-name ([push, ]<name>[ ,<addrsize>])</tt><label id="pragma-data-name"><p>
|
||||
|
||||
This pragma changes the name used for the DATA segment (the DATA segment
|
||||
is used to store initialized data). The argument is a string enclosed in
|
||||
double quotes.
|
||||
This pragma changes the name used for the DATA segment (the DATA segment is
|
||||
used to store initialized data). The <tt/name/ argument is a string enclosed
|
||||
in quotation marks.
|
||||
|
||||
Note: The default linker configuration file does only map the standard
|
||||
segments. If you use other segments, you have to create a new linker
|
||||
configuration file.
|
||||
<tt/addrsize/ is an optional string that gives a hint about where the
|
||||
<tt/name/ segment will be put in the CPU's address space. It describes the
|
||||
width of address numbers that point into that segment. Only words that
|
||||
are known to ca65 are allowed:
|
||||
<enum>
|
||||
<item>"zp", "zeropage", "direct"
|
||||
<item>"abs", "absolute", "near", "default"
|
||||
<item>"far"
|
||||
<item>"long", "dword"
|
||||
</enum>
|
||||
|
||||
The <tt/#pragma/ understands the push and pop parameters as explained above.
|
||||
Note: The default linker configuration file maps only the standard segments.
|
||||
If you use other segments, you must create a new linker configuration file.
|
||||
|
||||
Example:
|
||||
The <tt/#pragma/ understands the push and pop parameters, as explained above.
|
||||
|
||||
Examples:
|
||||
<tscreen><verb>
|
||||
#pragma data-name ("MyDATA")
|
||||
#pragma data-name ("MyDATA")
|
||||
#pragma data-name (push, "MyDATA")
|
||||
#pragma data-name ("MyDATA", "zeropage")
|
||||
</verb></tscreen>
|
||||
|
||||
|
||||
|
@ -1224,21 +1265,32 @@ parameter with the <tt/#pragma/.
|
|||
The <tt/#pragma/ understands the push and pop parameters as explained above.
|
||||
|
||||
|
||||
<sect1><tt>#pragma rodata-name ([push,] <name>)</tt><label id="pragma-rodata-name"><p>
|
||||
<sect1><tt>#pragma rodata-name ([push, ]<name>[ ,<addrsize>])</tt><label id="pragma-rodata-name"><p>
|
||||
|
||||
This pragma changes the name used for the RODATA segment (the RODATA
|
||||
segment is used to store readonly data). The argument is a string
|
||||
enclosed in double quotes.
|
||||
This pragma changes the name used for the RODATA segment (the RODATA segment
|
||||
is used to store read-only data). The <tt/name/ argument is a string enclosed
|
||||
in quotation marks.
|
||||
|
||||
Note: The default linker configuration file does only map the standard
|
||||
segments. If you use other segments, you have to create a new linker
|
||||
configuration file.
|
||||
<tt/addrsize/ is an optional string that gives a hint about where the
|
||||
<tt/name/ segment will be put in the CPU's address space. It describes the
|
||||
width of address numbers that point into that segment. Only words that
|
||||
are known to ca65 are allowed:
|
||||
<enum>
|
||||
<item>"zp", "zeropage", "direct"
|
||||
<item>"abs", "absolute", "near", "default"
|
||||
<item>"far"
|
||||
<item>"long", "dword"
|
||||
</enum>
|
||||
|
||||
The <tt/#pragma/ understands the push and pop parameters as explained above.
|
||||
Note: The default linker configuration file maps only the standard segments.
|
||||
If you use other segments, you must create a new linker configuration file.
|
||||
|
||||
Example:
|
||||
The <tt/#pragma/ understands the push and pop parameters, as explained above.
|
||||
|
||||
Examples:
|
||||
<tscreen><verb>
|
||||
#pragma rodata-name ("MyRODATA")
|
||||
#pragma rodata-name ("MyRODATA")
|
||||
#pragma rodata-name (push, "MyRODATA")
|
||||
</verb></tscreen>
|
||||
|
||||
|
||||
|
|
80
include/_atari5200os.h
Normal file
80
include/_atari5200os.h
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*****************************************************************************/
|
||||
/* */
|
||||
/* _atari5200os.h */
|
||||
/* */
|
||||
/* Internal include file, do not use directly */
|
||||
/* */
|
||||
/* */
|
||||
/* This software is provided 'as-is', without any expressed or implied */
|
||||
/* warranty. In no event will the authors be held liable for any damages */
|
||||
/* arising from the use of this software. */
|
||||
/* */
|
||||
/* Permission is granted to anyone to use this software for any purpose, */
|
||||
/* including commercial applications, and to alter it and redistribute it */
|
||||
/* freely, subject to the following restrictions: */
|
||||
/* */
|
||||
/* 1. The origin of this software must not be misrepresented; you must not */
|
||||
/* claim that you wrote the original software. If you use this software */
|
||||
/* in a product, an acknowledgment in the product documentation would be */
|
||||
/* appreciated but is not required. */
|
||||
/* 2. Altered source versions must be plainly marked as such, and must not */
|
||||
/* be misrepresented as being the original software. */
|
||||
/* 3. This notice may not be removed or altered from any source */
|
||||
/* distribution. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef __ATARI5200OS_H
|
||||
#define __ATARI5200OS_H
|
||||
|
||||
|
||||
struct __os {
|
||||
|
||||
/*Page zero*/
|
||||
unsigned char pokmsk; // = $00 System mask for POKEY IRQ enable
|
||||
unsigned char rtclok[2]; // = $01,$02 Real time clock
|
||||
unsigned char critic; // = $03 Critical section flag
|
||||
unsigned char atract; // = $04 Attract mode counter
|
||||
|
||||
union {
|
||||
struct {
|
||||
unsigned char sdlstl; // = $05 Save display list LO
|
||||
unsigned char sdlsth; // = $06 Save display list HI
|
||||
};
|
||||
void* sdlst; // = $05,$06 Display list shadow
|
||||
};
|
||||
|
||||
unsigned char sdmctl; // = $07 DMACTL shadow
|
||||
unsigned char pcolr0; // = $08 PM color 0
|
||||
unsigned char pcolr1; // = $09 PM color 1
|
||||
unsigned char pcolr2; // = $0A PM color 2
|
||||
unsigned char pcolr3; // = $0B PM color 3
|
||||
unsigned char color0; // = $0C PF color 0
|
||||
unsigned char color1; // = $0D PF color 1
|
||||
unsigned char color2; // = $0E PF color 2
|
||||
unsigned char color3; // = $0F PF color 3
|
||||
unsigned char color4; // = $10 PF color 4
|
||||
unsigned char _free_1[0xEF]; // = $11-$FF User space
|
||||
|
||||
/*Stack*/
|
||||
unsigned char stack[0x100]; // = $100-$1FF Stack
|
||||
|
||||
/*Page 2 OS variables*/
|
||||
void (*vinter)(void); // = $200 Immediate IRQ vector
|
||||
void (*vvblki)(void); // = $202 Immediate VBI vector
|
||||
void (*vvblkd)(void); // = $204 Deferred VBI vector
|
||||
void (*vdslst)(void); // = $206 DLI vector
|
||||
void (*vkeybd)(void); // = $208 Keyboard IRQ vector
|
||||
void (*vkeypd)(void); // = $20A Keyboard continuation vector
|
||||
void (*vbrkky)(void); // = $20C Break key interrupt vector
|
||||
void (*vbreak)(void); // = $20E BRK instruction interrupt vector
|
||||
void (*vserin)(void); // = $210 Serial input ready vector
|
||||
void (*vseror)(void); // = $212 Serial output data needed vector
|
||||
void (*vseroc)(void); // = $214 Serial output completed vector
|
||||
void (*vtimr1)(void); // = $216 POKEY timer 1 IRQ vector
|
||||
void (*vtimr2)(void); // = $218 POKEY timer 2 IRQ vector
|
||||
void (*vtimr4)(void); // = $21A POKEY timer 4 IRQ vector
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -65,6 +65,10 @@ extern void atr5200std_joy[]; /* referred to by joy_static_stddrv[] */
|
|||
#define AT_NTSC 0
|
||||
#define AT_PAL 1
|
||||
|
||||
/* Define variables used by the OS*/
|
||||
#include <_atari5200os.h>
|
||||
#define OS (*(struct __os*)0x0000)
|
||||
|
||||
/* define hardware */
|
||||
#include <_gtia.h>
|
||||
#define GTIA_READ (*(struct __gtia_read*)0xC000)
|
||||
|
|
|
@ -19,11 +19,14 @@
|
|||
.segment "ONCE"
|
||||
|
||||
initprompt:
|
||||
; Set prompt <> ']' to let DOS 3.3 know that we're
|
||||
; not in Applesoft immediate mode and thus keep it
|
||||
; from scanning our device I/O for DOS commands.
|
||||
; Set prompt <> ']' and currently executed Applesoft
|
||||
; line number hibyte <> $FF to let DOS 3.3 (at $A65E)
|
||||
; know that we're not in Applesoft immediate mode and
|
||||
; thus keep it from scanning our device I/O for DOS
|
||||
; commands.
|
||||
lda #$80 ; Same value used at $D52C
|
||||
sta PROMPT
|
||||
sta CURLIN+1 ; Any value <> $FF will do
|
||||
rts
|
||||
|
||||
.code
|
||||
|
|
|
@ -20,18 +20,19 @@
|
|||
|
||||
sta ptr3
|
||||
stx ptr3+1 ; save count as result
|
||||
eor #$FF
|
||||
sta ptr2
|
||||
txa
|
||||
eor #$FF
|
||||
sta ptr2+1 ; Remember -count-1
|
||||
|
||||
inx
|
||||
stx ptr2+1
|
||||
tax
|
||||
inx
|
||||
stx ptr2 ; save count with each byte incremented separately
|
||||
|
||||
jsr popptr1 ; get buf
|
||||
jsr popax ; get fd and discard
|
||||
|
||||
L1: inc ptr2
|
||||
L1: dec ptr2
|
||||
bnz L2
|
||||
inc ptr2+1
|
||||
dec ptr2+1
|
||||
bze L9 ; no more room in buf
|
||||
|
||||
; If there are no more characters in BASIC's input buffer, then get a line from
|
||||
|
|
|
@ -17,17 +17,17 @@
|
|||
sta ptr3
|
||||
stx ptr3+1 ; save count as result
|
||||
|
||||
eor #$FF
|
||||
sta ptr2
|
||||
txa
|
||||
eor #$FF
|
||||
sta ptr2+1 ; Remember -count-1
|
||||
inx
|
||||
stx ptr2+1
|
||||
tax
|
||||
inx
|
||||
stx ptr2 ; save count with each byte incremented separately
|
||||
|
||||
jsr popptr1 ; get buf
|
||||
jsr popax ; get fd and discard
|
||||
L1: inc ptr2
|
||||
L1: dec ptr2
|
||||
bne L2
|
||||
inc ptr2+1
|
||||
dec ptr2+1
|
||||
beq L9
|
||||
L2: ldy #0
|
||||
lda (ptr1),y
|
||||
|
|
|
@ -45,11 +45,11 @@
|
|||
|
||||
|
||||
_cbm_read:
|
||||
eor #$FF
|
||||
sta ptr1
|
||||
txa
|
||||
eor #$FF
|
||||
sta ptr1+1 ; Save -size-1
|
||||
inx
|
||||
stx ptr1+1
|
||||
tax
|
||||
inx
|
||||
stx ptr1 ; Save size with both bytes incremented separately.
|
||||
|
||||
jsr popax
|
||||
sta ptr2
|
||||
|
@ -92,9 +92,9 @@ _cbm_read:
|
|||
bne @L3
|
||||
inc ptr3+1 ; ++bytesread;
|
||||
|
||||
@L3: inc ptr1
|
||||
@L3: dec ptr1
|
||||
bne @L1
|
||||
inc ptr1+1
|
||||
dec ptr1+1
|
||||
bne @L1
|
||||
|
||||
@L4: jsr CLRCH
|
||||
|
|
|
@ -39,11 +39,11 @@
|
|||
_cbm_write:
|
||||
sta ptr3
|
||||
stx ptr3+1 ; Save size
|
||||
eor #$FF
|
||||
sta ptr1
|
||||
txa
|
||||
eor #$FF
|
||||
sta ptr1+1 ; Save -size-1
|
||||
inx
|
||||
stx ptr1+1
|
||||
tax
|
||||
inx
|
||||
stx ptr1 ; Save size with both bytes incremented separately
|
||||
|
||||
jsr popax
|
||||
sta ptr2
|
||||
|
@ -69,9 +69,9 @@ _cbm_write:
|
|||
|
||||
@L2: jsr BSOUT ; cbm_k_bsout (A);
|
||||
|
||||
@L3: inc ptr1 ; --size;
|
||||
@L3: dec ptr1 ; --size;
|
||||
bne @L1
|
||||
inc ptr1+1
|
||||
dec ptr1+1
|
||||
bne @L1
|
||||
|
||||
jsr CLRCH
|
||||
|
|
|
@ -106,9 +106,9 @@
|
|||
|
||||
; Decrement the count
|
||||
|
||||
@L3: inc ptr2
|
||||
@L3: dec ptr2
|
||||
bne @L0
|
||||
inc ptr2+1
|
||||
dec ptr2+1
|
||||
bne @L0
|
||||
beq done ; Branch always
|
||||
|
||||
|
|
|
@ -21,11 +21,11 @@
|
|||
|
||||
.proc rwcommon
|
||||
|
||||
eor #$FF
|
||||
sta ptr2
|
||||
txa
|
||||
eor #$FF
|
||||
sta ptr2+1 ; Remember -count-1
|
||||
inx
|
||||
stx ptr2+1
|
||||
tax
|
||||
inx
|
||||
stx ptr2 ; Save count with each byte incremented separately
|
||||
|
||||
jsr popptr1 ; Get buf to ptr1, Y=0 by call
|
||||
|
||||
|
|
|
@ -83,9 +83,9 @@
|
|||
|
||||
; Decrement count
|
||||
|
||||
@L2: inc ptr2
|
||||
@L2: dec ptr2
|
||||
bne @L0
|
||||
inc ptr2+1
|
||||
dec ptr2+1
|
||||
bne @L0
|
||||
|
||||
; Wrote all chars or disk full. Close the output channel
|
||||
|
|
|
@ -17,22 +17,22 @@
|
|||
|
||||
.proc _getcwd
|
||||
|
||||
; Remember -size-1 because this simplifies the following loop
|
||||
; Remember size with each byte incremented because this simplifies the following loop
|
||||
|
||||
eor #$FF
|
||||
sta ptr2
|
||||
txa
|
||||
eor #$FF
|
||||
sta ptr2+1
|
||||
inx
|
||||
stx ptr2+1
|
||||
tax
|
||||
inx
|
||||
stx ptr2 ; Save size with each byte incremented separately
|
||||
|
||||
jsr popptr1 ; Get buf to ptr1
|
||||
|
||||
; Copy __cwd to the given buffer checking the length
|
||||
|
||||
; ldy #$00 is guaranteed by popptr1
|
||||
loop: inc ptr2
|
||||
loop: dec ptr2
|
||||
bne @L1
|
||||
inc ptr2+1
|
||||
dec ptr2+1
|
||||
beq overflow
|
||||
|
||||
; Copy one character, end the loop if the zero terminator is reached. We
|
||||
|
|
|
@ -10,14 +10,14 @@
|
|||
|
||||
_memcmp:
|
||||
|
||||
; Calculate (-count-1) and store it into ptr3. This is some overhead here but
|
||||
; saves time in the compare loop
|
||||
; Calculate a special count, and store it into ptr3. That is some overhead here,
|
||||
; but saves time in the compare loop
|
||||
|
||||
eor #$FF
|
||||
sta ptr3
|
||||
txa
|
||||
eor #$FF
|
||||
sta ptr3+1
|
||||
inx
|
||||
stx ptr3+1
|
||||
tax
|
||||
inx
|
||||
stx ptr3 ; Save count with each byte incremented separately
|
||||
|
||||
; Get the pointer parameters
|
||||
|
||||
|
@ -29,12 +29,12 @@ _memcmp:
|
|||
; Loop initialization
|
||||
|
||||
;ldy #$00 ; Initialize pointer (Y=0 guaranteed by popptr1)
|
||||
ldx ptr3 ; Load low counter byte into X
|
||||
ldx ptr3 ; Load inner counter byte into .X
|
||||
|
||||
; Head of compare loop: Test for the end condition
|
||||
|
||||
Loop: inx ; Bump low byte of (-count-1)
|
||||
beq BumpHiCnt ; Jump on overflow
|
||||
Loop: dex
|
||||
beq BumpHiCnt ; Jump on end of inner count
|
||||
|
||||
; Do the compare
|
||||
|
||||
|
@ -50,10 +50,10 @@ Comp: lda (ptr1),y
|
|||
inc ptr2+1
|
||||
bne Loop ; Branch always (pointer wrap is illegal)
|
||||
|
||||
; Entry on low counter byte overflow
|
||||
; Entry on inner loop end
|
||||
|
||||
BumpHiCnt:
|
||||
inc ptr3+1 ; Bump high byte of (-count-1)
|
||||
dec ptr3+1
|
||||
bne Comp ; Jump if not done
|
||||
jmp return0 ; Count is zero, areas are identical
|
||||
|
||||
|
@ -67,4 +67,3 @@ NotEqual:
|
|||
Greater:
|
||||
ldx #$01 ; Make result positive
|
||||
rts
|
||||
|
||||
|
|
|
@ -5,17 +5,17 @@
|
|||
; char* strncat (char* dest, const char* src, size_t n);
|
||||
;
|
||||
|
||||
.export _strncat
|
||||
.import popax, popptr1
|
||||
.importzp ptr1, ptr2, ptr3, tmp1, tmp2
|
||||
.macpack cpu
|
||||
.export _strncat
|
||||
.import popax, popptr1
|
||||
.importzp ptr1, ptr2, ptr3, tmp1, tmp2
|
||||
.macpack cpu
|
||||
|
||||
_strncat:
|
||||
eor #$FF ; one's complement to count upwards
|
||||
sta tmp1
|
||||
txa
|
||||
eor #$FF
|
||||
sta tmp2
|
||||
inx
|
||||
stx tmp2
|
||||
tax
|
||||
inx
|
||||
stx tmp1 ; save count with each byte incremented separately
|
||||
|
||||
jsr popptr1 ; get src
|
||||
|
||||
|
@ -49,9 +49,9 @@ L2: sty ptr2
|
|||
L3: ldy #0
|
||||
ldx tmp1 ; low counter byte
|
||||
|
||||
L4: inx
|
||||
L4: dex
|
||||
bne L5
|
||||
inc tmp2
|
||||
dec tmp2
|
||||
beq L6 ; jump if done
|
||||
L5: lda (ptr1),y
|
||||
sta (ptr2),y
|
||||
|
|
|
@ -10,11 +10,11 @@
|
|||
|
||||
.proc _strncpy
|
||||
|
||||
eor #$FF
|
||||
sta tmp1
|
||||
txa
|
||||
eor #$FF
|
||||
sta tmp2 ; Store -size - 1
|
||||
inx
|
||||
stx tmp2
|
||||
tax
|
||||
inx
|
||||
stx tmp1 ; save count with each byte incremented separately
|
||||
|
||||
jsr popptr1 ; get src
|
||||
jsr popax ; get dest
|
||||
|
@ -24,11 +24,11 @@
|
|||
|
||||
; Copy src -> dest up to size bytes
|
||||
|
||||
ldx tmp1 ; Load low byte of ones complement of size
|
||||
ldx tmp1
|
||||
ldy #$00
|
||||
L1: inx
|
||||
L1: dex
|
||||
bne L2
|
||||
inc tmp2
|
||||
dec tmp2
|
||||
beq L9
|
||||
|
||||
L2: lda (ptr1),y ; Copy one character
|
||||
|
@ -42,8 +42,8 @@ L2: lda (ptr1),y ; Copy one character
|
|||
|
||||
; Fill the remaining bytes.
|
||||
|
||||
L3: inx ; Counter low byte
|
||||
beq L6 ; Branch on overflow
|
||||
L3: dex ; Counter low byte
|
||||
beq L6
|
||||
L4: sta (ptr2),y ; Clear one byte
|
||||
L5: iny ; Bump pointer
|
||||
bne L3
|
||||
|
@ -52,7 +52,7 @@ L5: iny ; Bump pointer
|
|||
|
||||
; Bump the counter high byte
|
||||
|
||||
L6: inc tmp2
|
||||
L6: dec tmp2
|
||||
bne L4
|
||||
|
||||
; Done, return dest
|
||||
|
|
|
@ -15,17 +15,11 @@
|
|||
_strnicmp:
|
||||
_strncasecmp:
|
||||
|
||||
; Convert the given counter value in a/x from a downward counter into an
|
||||
; upward counter, so we can increment the counter in the loop below instead
|
||||
; of decrementing it. This adds some overhead now, but is cheaper than
|
||||
; executing a more complex test in each iteration of the loop. We do also
|
||||
; correct the value by one, so we can do the test on top of the loop.
|
||||
|
||||
eor #$FF
|
||||
sta ptr3
|
||||
txa
|
||||
eor #$FF
|
||||
sta ptr3+1
|
||||
inx
|
||||
stx ptr3+1
|
||||
tax
|
||||
inx
|
||||
stx ptr3 ; save count with each byte incremented separately
|
||||
|
||||
; Get the remaining arguments
|
||||
|
||||
|
@ -40,8 +34,8 @@ _strncasecmp:
|
|||
|
||||
; Start of compare loop. Check the counter.
|
||||
|
||||
Loop: inc ptr3
|
||||
beq IncHi ; increment high byte
|
||||
Loop: dec ptr3 ; decrement high byte
|
||||
beq IncHi
|
||||
|
||||
; Compare a byte from the strings
|
||||
|
||||
|
@ -79,7 +73,7 @@ L2: ldx tmp1
|
|||
|
||||
; Increment hi byte
|
||||
|
||||
IncHi: inc ptr3+1
|
||||
IncHi: dec ptr3+1
|
||||
bne Comp ; jump if counter not zero
|
||||
|
||||
; Exit code if strings are equal. a/x not set
|
||||
|
|
|
@ -47,12 +47,12 @@ outdesc: ; Static outdesc structure
|
|||
|
||||
out: jsr popax ; count
|
||||
sta ptr2
|
||||
eor #$FF
|
||||
sta outdesc+6
|
||||
txa
|
||||
sta ptr2+1
|
||||
eor #$FF
|
||||
sta outdesc+7
|
||||
stx ptr2+1
|
||||
inx
|
||||
stx outdesc+7
|
||||
tax
|
||||
inx
|
||||
stx outdesc+6
|
||||
|
||||
jsr popptr1 ; buf
|
||||
|
||||
|
@ -74,7 +74,7 @@ out: jsr popax ; count
|
|||
|
||||
; Loop outputting characters
|
||||
|
||||
@L1: inc outdesc+6
|
||||
@L1: dec outdesc+6
|
||||
beq @L4
|
||||
@L2: ldy tmp1
|
||||
lda (ptr1),y
|
||||
|
@ -85,7 +85,7 @@ out: jsr popax ; count
|
|||
jsr _cputc
|
||||
jmp @L1
|
||||
|
||||
@L4: inc outdesc+7
|
||||
@L4: dec outdesc+7
|
||||
bne @L2
|
||||
rts
|
||||
|
||||
|
|
|
@ -94,11 +94,12 @@ _read:
|
|||
; popax - fd, must be == to the above one
|
||||
; return -1+__oserror or number of bytes read
|
||||
|
||||
eor #$ff
|
||||
sta ptr1
|
||||
txa
|
||||
eor #$ff
|
||||
sta ptr1+1 ; -(# of bytes to read)-1
|
||||
inx
|
||||
stx ptr1+1
|
||||
tax
|
||||
inx
|
||||
stx ptr1 ; save count with each byte incremented separately
|
||||
|
||||
jsr popax
|
||||
sta ptr2
|
||||
stx ptr2+1 ; buffer ptr
|
||||
|
@ -152,9 +153,9 @@ _read:
|
|||
beq @done ; yes, we're done
|
||||
jmp __mappederrno ; no, we're screwed
|
||||
|
||||
@L3: inc ptr1 ; decrement the count
|
||||
@L3: dec ptr1 ; decrement the count
|
||||
bne @L0
|
||||
inc ptr1+1
|
||||
dec ptr1+1
|
||||
bne @L0
|
||||
|
||||
@done:
|
||||
|
|
|
@ -50,16 +50,15 @@ LINEDIST = $20 ; Offset in video RAM between two lines
|
|||
ldx #>load_addr
|
||||
sta load
|
||||
stx load+1
|
||||
lda #<load_size
|
||||
eor #$FF
|
||||
sta count ; store (-size - 1)
|
||||
lda #>load_size
|
||||
eor #$FF
|
||||
sta count+1
|
||||
|
||||
L1: inc count ; pre-count one's-complement upwards
|
||||
ldx #(<load_size) + 1
|
||||
stx count
|
||||
ldx #(>load_size) + 1
|
||||
stx count+1 ; save size with each byte incremented separately
|
||||
|
||||
L1: dec count
|
||||
bnz L2
|
||||
inc count+1
|
||||
dec count+1
|
||||
bze L3
|
||||
L2: jsr GETCHAR ; (doesn't change .Y)
|
||||
sta (load),y
|
||||
|
|
|
@ -13,11 +13,11 @@
|
|||
sta ptr3
|
||||
stx ptr3+1 ; save count as result
|
||||
|
||||
eor #$FF
|
||||
sta ptr2
|
||||
txa
|
||||
eor #$FF
|
||||
sta ptr2+1 ; remember -count-1
|
||||
inx
|
||||
stx ptr2+1
|
||||
tax
|
||||
inx
|
||||
stx ptr2 ; save count with each byte incremented separately
|
||||
|
||||
jsr popptr1 ; get buf
|
||||
jsr popax ; get fd and discard
|
||||
|
@ -51,9 +51,9 @@ next:
|
|||
rts
|
||||
|
||||
|
||||
L1: inc ptr2
|
||||
L1: dec ptr2
|
||||
bne L2
|
||||
inc ptr2+1
|
||||
dec ptr2+1
|
||||
beq L9
|
||||
L2: ldy #0
|
||||
lda (ptr1),y
|
||||
|
|
|
@ -1433,17 +1433,20 @@ unsigned g_typeadjust (unsigned lhs, unsigned rhs)
|
|||
|
||||
/* Note that this logic is largely duplicated by ArithmeticConvert. */
|
||||
|
||||
/* Before we apply the integral promotions, we check if both types are unsigned char.
|
||||
** If so, we return unsigned int, rather than int, which would be returned by the standard
|
||||
** rules. This is only a performance optimization and does not affect correctness, as
|
||||
** the flags are only used for code generation, and not to determine types of other
|
||||
** expressions containing this one. All unsigned char bit-patterns are valid as both int
|
||||
** and unsigned int and represent the same value, so either signed or unsigned int operations
|
||||
** can be used. This special case part is not duplicated by ArithmeticConvert.
|
||||
/* Before we apply the integral promotions, we check if both types are the same character type.
|
||||
** If so, we return that type, rather than int, which would be returned by the standard
|
||||
** rules. This is only a performance optimization allowing the use of unsigned and/or char
|
||||
** operations; it does not affect correctness, as the flags are only used for code generation,
|
||||
** and not to determine types of other expressions containing this one. For codgen, CF_CHAR
|
||||
** means the operands are char and the result is int (unless CF_FORCECHAR is also set, in
|
||||
** which case the result is char). This special case part is not duplicated by
|
||||
** ArithmeticConvert.
|
||||
*/
|
||||
if ((lhs & CF_TYPEMASK) == CF_CHAR && (lhs & CF_UNSIGNED) &&
|
||||
(rhs & CF_TYPEMASK) == CF_CHAR && (rhs & CF_UNSIGNED)) {
|
||||
return const_flag | CF_UNSIGNED | CF_INT;
|
||||
if ((lhs & CF_TYPEMASK) == CF_CHAR && (rhs & CF_TYPEMASK) == CF_CHAR &&
|
||||
(lhs & CF_UNSIGNED) == (rhs & CF_UNSIGNED)) {
|
||||
/* Signedness flags are the same, so just use one of them. */
|
||||
const unsigned unsigned_flag = lhs & CF_UNSIGNED;
|
||||
return const_flag | unsigned_flag | CF_CHAR;
|
||||
}
|
||||
|
||||
/* Apply integral promotions for types char/short. */
|
||||
|
@ -3111,9 +3114,26 @@ void g_asr (unsigned flags, unsigned long val)
|
|||
switch (flags & CF_TYPEMASK) {
|
||||
case CF_CHAR:
|
||||
if (flags & CF_FORCECHAR) {
|
||||
if ((flags & CF_UNSIGNED) != 0 && val < 8) {
|
||||
while (val--) {
|
||||
AddCodeLine ("lsr a");
|
||||
val &= 7;
|
||||
if ((flags & CF_UNSIGNED) != 0) {
|
||||
/* Instead of `val` right shifts, we can also do `9 - val` left rotates
|
||||
** and a mask. This saves 3 bytes and 8 cycles for `val == 7` and
|
||||
** 1 byte and 4 cycles for `val == 6`.
|
||||
*/
|
||||
if (val < 6) {
|
||||
while (val--) {
|
||||
AddCodeLine ("lsr a"); /* 1 byte, 2 cycles */
|
||||
}
|
||||
} else {
|
||||
unsigned i;
|
||||
/* The first ROL shifts in garbage and sets carry to the high bit.
|
||||
** The garbage is cleaned up by the mask.
|
||||
*/
|
||||
for (i = val; i < 9; ++i) {
|
||||
AddCodeLine ("rol a"); /* 1 byte, 2 cycles */
|
||||
}
|
||||
/* 2 bytes, 2 cycles */
|
||||
AddCodeLine ("and #$%02X", 0xFF >> val);
|
||||
}
|
||||
return;
|
||||
} else if (val <= 2) {
|
||||
|
@ -3267,9 +3287,21 @@ void g_asl (unsigned flags, unsigned long val)
|
|||
if (flags & CF_CONST) {
|
||||
switch (flags & CF_TYPEMASK) {
|
||||
case CF_CHAR:
|
||||
if ((flags & CF_FORCECHAR) != 0 && val <= 6) {
|
||||
while (val--) {
|
||||
AddCodeLine ("asl a");
|
||||
if ((flags & CF_FORCECHAR) != 0) {
|
||||
val &= 7;
|
||||
/* Large shifts are faster and smaller with ROR. See g_asr for detailed
|
||||
** byte and cycle counts.
|
||||
*/
|
||||
if (val < 6) {
|
||||
while (val--) {
|
||||
AddCodeLine ("asl a");
|
||||
}
|
||||
} else {
|
||||
unsigned i;
|
||||
for (i = val; i < 9; ++i) {
|
||||
AddCodeLine ("ror a");
|
||||
}
|
||||
AddCodeLine ("and #$%02X", (~0U << val) & 0xFF);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -287,7 +287,7 @@ static unsigned Opt_tosshift (StackOpData* D, const char* Name)
|
|||
/* ldx */
|
||||
X = NewCodeEntry (OP65_LDX, LoadX->AM, LoadX->Arg, 0, D->OpEntry->LI);
|
||||
InsertEntry (D, X, D->IP++);
|
||||
|
||||
|
||||
/* Lhs load entries can be removed if not used later */
|
||||
D->Lhs.X.Flags |= LI_REMOVE;
|
||||
D->Lhs.A.Flags |= LI_REMOVE;
|
||||
|
@ -1100,7 +1100,7 @@ static unsigned Opt_tosxorax (StackOpData* D)
|
|||
|
||||
|
||||
static unsigned Opt_a_toscmpbool (StackOpData* D, const char* BoolTransformer)
|
||||
/* Optimize the tos compare sequence with a bool transformer */
|
||||
/* Optimize the TOS compare sequence with a bool transformer */
|
||||
{
|
||||
CodeEntry* X;
|
||||
cmp_t Cond;
|
||||
|
@ -1119,9 +1119,8 @@ static unsigned Opt_a_toscmpbool (StackOpData* D, const char* BoolTransformer)
|
|||
D->Rhs.A.Flags |= LI_REMOVE;
|
||||
|
||||
} else if ((D->Lhs.A.Flags & LI_DIRECT) != 0) {
|
||||
|
||||
/* If the lhs is direct (but not stack relative), encode compares with lhs
|
||||
** effectively reverting the order (which doesn't matter for ==).
|
||||
/* If the lhs is direct (but not stack relative), encode compares with lhs,
|
||||
** effectively reversing the order (which doesn't matter for == and !=).
|
||||
*/
|
||||
Cond = FindBoolCmpCond (BoolTransformer);
|
||||
Cond = GetRevertedCond (Cond);
|
||||
|
@ -1138,7 +1137,6 @@ static unsigned Opt_a_toscmpbool (StackOpData* D, const char* BoolTransformer)
|
|||
D->Lhs.A.Flags |= LI_REMOVE;
|
||||
|
||||
} else {
|
||||
|
||||
/* We'll do reverse-compare */
|
||||
Cond = FindBoolCmpCond (BoolTransformer);
|
||||
Cond = GetRevertedCond (Cond);
|
||||
|
@ -1162,7 +1160,7 @@ static unsigned Opt_a_toscmpbool (StackOpData* D, const char* BoolTransformer)
|
|||
X = NewCodeEntry (OP65_JSR, AM65_ABS, BoolTransformer, 0, D->OpEntry->LI);
|
||||
InsertEntry (D, X, D->IP++);
|
||||
|
||||
/* Remove the push and the call to the tosgeax function */
|
||||
/* Remove the push and the call to the TOS function */
|
||||
RemoveRemainders (D);
|
||||
|
||||
/* We changed the sequence */
|
||||
|
@ -1179,22 +1177,6 @@ static unsigned Opt_a_toseq (StackOpData* D)
|
|||
|
||||
|
||||
|
||||
static unsigned Opt_a_tosge (StackOpData* D)
|
||||
/* Optimize the tosgeax sequence */
|
||||
{
|
||||
return Opt_a_toscmpbool (D, "boolge");
|
||||
}
|
||||
|
||||
|
||||
|
||||
static unsigned Opt_a_tosgt (StackOpData* D)
|
||||
/* Optimize the tosgtax sequence */
|
||||
{
|
||||
return Opt_a_toscmpbool (D, "boolgt");
|
||||
}
|
||||
|
||||
|
||||
|
||||
static unsigned Opt_a_tosicmp (StackOpData* D)
|
||||
/* Replace tosicmp with CMP */
|
||||
{
|
||||
|
@ -1236,7 +1218,7 @@ static unsigned Opt_a_tosicmp (StackOpData* D)
|
|||
}
|
||||
InsertEntry (D, X, D->IP++);
|
||||
|
||||
/* cmp src,y OR cmp (sp),y*/
|
||||
/* cmp src,y OR cmp (sp),y */
|
||||
if (D->Rhs.A.LoadEntry->OPC == OP65_JSR) {
|
||||
/* opc (sp),y */
|
||||
X = NewCodeEntry (OP65_CMP, AM65_ZP_INDY, "sp", 0, D->OpEntry->LI);
|
||||
|
@ -1268,18 +1250,18 @@ static unsigned Opt_a_tosicmp (StackOpData* D)
|
|||
InsertEntry (D, X, D->IP-3);
|
||||
|
||||
} else {
|
||||
/* Just clear A,Z,N and set C */
|
||||
/* Just clear A,Z,N; and set C */
|
||||
Arg = MakeHexArg (0);
|
||||
if ((RI = GetLastChangedRegInfo (D, &D->Lhs.A)) != 0 &&
|
||||
RegValIsKnown (RI->Out.RegA) &&
|
||||
(RI->Out.RegA & 0xFF) == 0) {
|
||||
Arg = MakeHexArg (0);
|
||||
X = NewCodeEntry (OP65_CMP, AM65_IMM, Arg, 0, D->OpEntry->LI);
|
||||
|
||||
X = NewCodeEntry (OP65_CMP, AM65_IMM, Arg, 0, D->OpEntry->LI);
|
||||
InsertEntry (D, X, D->OpIndex + 1);
|
||||
} else {
|
||||
Arg = MakeHexArg (0);
|
||||
X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, D->OpEntry->LI);
|
||||
X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, D->OpEntry->LI);
|
||||
InsertEntry (D, X, D->OpIndex + 1);
|
||||
X = NewCodeEntry (OP65_CMP, AM65_IMM, Arg, 0, D->OpEntry->LI);
|
||||
X = NewCodeEntry (OP65_CMP, AM65_IMM, Arg, 0, D->OpEntry->LI);
|
||||
InsertEntry (D, X, D->OpIndex + 2);
|
||||
}
|
||||
}
|
||||
|
@ -1292,24 +1274,8 @@ static unsigned Opt_a_tosicmp (StackOpData* D)
|
|||
|
||||
|
||||
|
||||
static unsigned Opt_a_tosle (StackOpData* D)
|
||||
/* Optimize the tosleax sequence */
|
||||
{
|
||||
return Opt_a_toscmpbool (D, "boolle");
|
||||
}
|
||||
|
||||
|
||||
|
||||
static unsigned Opt_a_toslt (StackOpData* D)
|
||||
/* Optimize the tosltax sequence */
|
||||
{
|
||||
return Opt_a_toscmpbool (D, "boollt");
|
||||
}
|
||||
|
||||
|
||||
|
||||
static unsigned Opt_a_tosne (StackOpData* D)
|
||||
/* Optimize the toseqax sequence */
|
||||
/* Optimize the tosneax sequence */
|
||||
{
|
||||
return Opt_a_toscmpbool (D, "boolne");
|
||||
}
|
||||
|
@ -1317,7 +1283,7 @@ static unsigned Opt_a_tosne (StackOpData* D)
|
|||
|
||||
|
||||
static unsigned Opt_a_tosuge (StackOpData* D)
|
||||
/* Optimize the tosugeax sequence */
|
||||
/* Optimize the tosgeax and tosugeax sequences */
|
||||
{
|
||||
return Opt_a_toscmpbool (D, "booluge");
|
||||
}
|
||||
|
@ -1325,7 +1291,7 @@ static unsigned Opt_a_tosuge (StackOpData* D)
|
|||
|
||||
|
||||
static unsigned Opt_a_tosugt (StackOpData* D)
|
||||
/* Optimize the tosugtax sequence */
|
||||
/* Optimize the tosgtax and tosugtax sequences */
|
||||
{
|
||||
return Opt_a_toscmpbool (D, "boolugt");
|
||||
}
|
||||
|
@ -1333,7 +1299,7 @@ static unsigned Opt_a_tosugt (StackOpData* D)
|
|||
|
||||
|
||||
static unsigned Opt_a_tosule (StackOpData* D)
|
||||
/* Optimize the tosuleax sequence */
|
||||
/* Optimize the tosleax and tosuleax sequences */
|
||||
{
|
||||
return Opt_a_toscmpbool (D, "boolule");
|
||||
}
|
||||
|
@ -1341,7 +1307,7 @@ static unsigned Opt_a_tosule (StackOpData* D)
|
|||
|
||||
|
||||
static unsigned Opt_a_tosult (StackOpData* D)
|
||||
/* Optimize the tosultax sequence */
|
||||
/* Optimize the tosltax and tosultax sequences */
|
||||
{
|
||||
return Opt_a_toscmpbool (D, "boolult");
|
||||
}
|
||||
|
@ -1354,6 +1320,8 @@ static unsigned Opt_a_tosult (StackOpData* D)
|
|||
|
||||
|
||||
|
||||
/* The first column of these two tables must be sorted in lexical order */
|
||||
|
||||
static const OptFuncDesc FuncTable[] = {
|
||||
{ "__bzero", Opt___bzero, REG_NONE, OP_X_ZERO | OP_A_KNOWN },
|
||||
{ "staspidx", Opt_staspidx, REG_NONE, OP_NONE },
|
||||
|
@ -1379,11 +1347,11 @@ static const OptFuncDesc FuncTable[] = {
|
|||
|
||||
static const OptFuncDesc FuncRegATable[] = {
|
||||
{ "toseqax", Opt_a_toseq, REG_NONE, OP_NONE },
|
||||
{ "tosgeax", Opt_a_tosge, REG_NONE, OP_NONE },
|
||||
{ "tosgtax", Opt_a_tosgt, REG_NONE, OP_NONE },
|
||||
{ "tosgeax", Opt_a_tosuge, REG_NONE, OP_NONE },
|
||||
{ "tosgtax", Opt_a_tosugt, REG_NONE, OP_NONE },
|
||||
{ "tosicmp", Opt_a_tosicmp, REG_NONE, OP_NONE },
|
||||
{ "tosleax", Opt_a_tosle, REG_NONE, OP_NONE },
|
||||
{ "tosltax", Opt_a_toslt, REG_NONE, OP_NONE },
|
||||
{ "tosleax", Opt_a_tosule, REG_NONE, OP_NONE },
|
||||
{ "tosltax", Opt_a_tosult, REG_NONE, OP_NONE },
|
||||
{ "tosneax", Opt_a_tosne, REG_NONE, OP_NONE },
|
||||
{ "tosugeax", Opt_a_tosuge, REG_NONE, OP_NONE },
|
||||
{ "tosugtax", Opt_a_tosugt, REG_NONE, OP_NONE },
|
||||
|
|
|
@ -74,6 +74,7 @@ IntStack WarnUnknownPragma = INTSTACK(1); /* - unknown #pragmas */
|
|||
IntStack WarnUnusedLabel = INTSTACK(1); /* - unused labels */
|
||||
IntStack WarnUnusedParam = INTSTACK(1); /* - unused parameters */
|
||||
IntStack WarnUnusedVar = INTSTACK(1); /* - unused variables */
|
||||
IntStack WarnReturnType = INTSTACK(1); /* - control reaches end of non-void function */
|
||||
|
||||
/* Map the name of a warning to the intstack that holds its state */
|
||||
typedef struct WarnMapEntry WarnMapEntry;
|
||||
|
@ -92,6 +93,7 @@ static WarnMapEntry WarnMap[] = {
|
|||
{ &WarnUnusedLabel, "unused-label" },
|
||||
{ &WarnUnusedParam, "unused-param" },
|
||||
{ &WarnUnusedVar, "unused-var" },
|
||||
{ &WarnReturnType, "return-type" },
|
||||
};
|
||||
|
||||
Collection DiagnosticStrBufs;
|
||||
|
|
|
@ -71,6 +71,7 @@ extern IntStack WarnUnknownPragma; /* - unknown #pragmas */
|
|||
extern IntStack WarnUnusedLabel; /* - unused labels */
|
||||
extern IntStack WarnUnusedParam; /* - unused parameters */
|
||||
extern IntStack WarnUnusedVar; /* - unused variables */
|
||||
extern IntStack WarnReturnType; /* - control reaches end of non-void function */
|
||||
|
||||
/* Forward */
|
||||
struct StrBuf;
|
||||
|
|
|
@ -23,10 +23,10 @@
|
|||
|
||||
|
||||
|
||||
#define SQP_KEEP_NONE 0x00
|
||||
#define SQP_KEEP_TEST 0x01U
|
||||
#define SQP_KEEP_EAX 0x02U
|
||||
#define SQP_KEEP_EXPR 0x03U /* SQP_KEEP_TEST | SQP_KEEP_EAX */
|
||||
#define SQP_KEEP_NONE 0x00
|
||||
#define SQP_KEEP_TEST 0x01U
|
||||
#define SQP_KEEP_EAX 0x02U
|
||||
#define SQP_KEEP_EXPR 0x03U /* SQP_KEEP_TEST | SQP_KEEP_EAX */
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -654,8 +654,8 @@ void NewFunc (SymEntry* Func, FuncDesc* D)
|
|||
** environment returning int, output a warning if we didn't see a return
|
||||
** statement.
|
||||
*/
|
||||
if (!F_HasVoidReturn (CurrentFunc) && !F_HasReturn (CurrentFunc) && !C99MainFunc) {
|
||||
Warning ("Control reaches end of non-void function");
|
||||
if (!F_HasVoidReturn (CurrentFunc) && !F_HasReturn (CurrentFunc) && !C99MainFunc && IS_Get (&WarnReturnType)) {
|
||||
Warning ("Control reaches end of non-void function [-Wreturn-type]");
|
||||
}
|
||||
|
||||
/* If this is the main function in a C99 environment returning an int, let
|
||||
|
|
|
@ -117,14 +117,6 @@ $(WORKDIR)/endless.$1.$2.prg: endless.c | $(WORKDIR)
|
|||
$(LD65) -t sim$2 -o $$@ $$(@:.prg=.o) sim$2.lib $(NULLERR)
|
||||
$(NOT) $(SIM65) $(SIM65FLAGS) $$@ $(NULLOUT) $(NULLERR)
|
||||
|
||||
# this one fails when optimization are enabled
|
||||
$(WORKDIR)/bug1348.$1.$2.prg: bug1348.c | $(WORKDIR)
|
||||
$(if $(QUIET),echo misc/bug1348.$1.$2.prg)
|
||||
$(CC65) -Osr -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)
|
||||
|
||||
# these need reference data that can't be generated by a host-compiled program,
|
||||
# in a useful way
|
||||
$(WORKDIR)/limits.$1.$2.prg: limits.c $(ISEQUAL) | $(WORKDIR)
|
||||
|
|
1044
test/val/binlit.c
1044
test/val/binlit.c
File diff suppressed because it is too large
Load Diff
|
@ -7,24 +7,24 @@
|
|||
|
||||
struct ImageStruct
|
||||
{
|
||||
uint8_t _imageData;
|
||||
#if !defined(NO_COLOR)
|
||||
uint8_t _color;
|
||||
#endif
|
||||
uint8_t _imageData;
|
||||
#if !defined(NO_COLOR)
|
||||
uint8_t _color;
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef struct ImageStruct Image;
|
||||
|
||||
struct CharacterStruct
|
||||
{
|
||||
// character coordinates
|
||||
uint8_t _x;
|
||||
uint8_t _y;
|
||||
// character coordinates
|
||||
uint8_t _x;
|
||||
uint8_t _y;
|
||||
|
||||
// _status decides whether the character is active
|
||||
uint8_t _status;
|
||||
// _status decides whether the character is active
|
||||
uint8_t _status;
|
||||
|
||||
Image* _imagePtr;
|
||||
Image* _imagePtr;
|
||||
};
|
||||
|
||||
typedef struct CharacterStruct Character;
|
||||
|
@ -53,20 +53,20 @@ Character bombs[BOMBS_NUMBER];
|
|||
|
||||
uint16_t test1(void)
|
||||
{
|
||||
if((loop<MAX_GHOST_LOOP) && (ghostLevel<MAX_GHOST_LEVEL))
|
||||
{
|
||||
return INITIAL_GHOST_SLOWDOWN-(uint16_t)level*256-ghostLevel*8;
|
||||
}
|
||||
return GHOST_MIN_SLOWDOWN;
|
||||
if((loop<MAX_GHOST_LOOP) && (ghostLevel<MAX_GHOST_LEVEL))
|
||||
{
|
||||
return INITIAL_GHOST_SLOWDOWN-(uint16_t)level*256-ghostLevel*8;
|
||||
}
|
||||
return GHOST_MIN_SLOWDOWN;
|
||||
}
|
||||
|
||||
uint16_t test2(void)
|
||||
{
|
||||
if((loop<MAX_GHOST_LOOP) && (ghostLevel<MAX_GHOST_LEVEL))
|
||||
{
|
||||
return INITIAL_GHOST_SLOWDOWN-(uint16_t)level*256-ghostLevel*16;
|
||||
}
|
||||
return GHOST_MIN_SLOWDOWN;
|
||||
if((loop<MAX_GHOST_LOOP) && (ghostLevel<MAX_GHOST_LEVEL))
|
||||
{
|
||||
return INITIAL_GHOST_SLOWDOWN-(uint16_t)level*256-ghostLevel*16;
|
||||
}
|
||||
return GHOST_MIN_SLOWDOWN;
|
||||
}
|
||||
|
||||
uint16_t res = 0;
|
||||
|
|
|
@ -1,27 +1,26 @@
|
|||
|
||||
/* bug#1348, wrongly optimized integer promotion in comparison */
|
||||
/* bug #1348, wrongly optimized integer promotion in comparison */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int notrandtab[] = {
|
||||
static const int notrandtab[] = {
|
||||
0xffff, 0x7fff, 0x3fff, 0x1fff,
|
||||
0x0fff, 0x07ff, 0x03ff, 0x01ff,
|
||||
0x00ff, 0x007f, 0x003f, 0x001f,
|
||||
0x000f, 0x0007, 0x0003, 0x0001
|
||||
};
|
||||
|
||||
unsigned char notrandcount = 0;
|
||||
static unsigned char notrandcount = 0;
|
||||
|
||||
int notrand(void)
|
||||
static int notrand(void)
|
||||
{
|
||||
return notrandtab[notrandcount & 0x0f];
|
||||
}
|
||||
|
||||
unsigned char n1, n2;
|
||||
unsigned char i, ii, s;
|
||||
unsigned char err = 0;
|
||||
static unsigned char n1, n2;
|
||||
static unsigned char i, ii, s;
|
||||
static unsigned char err = 0;
|
||||
|
||||
unsigned char cmptab[] = {
|
||||
static const unsigned char cmptab[] = {
|
||||
0xff, 0x7f, 0x3f, 0x1f,
|
||||
0x0f, 0x07, 0x03, 0x01,
|
||||
0x80, 0x40, 0x20, 0x10,
|
||||
|
@ -40,13 +39,14 @@ int main(void)
|
|||
if ((notrand() & 0xffu) > s) {
|
||||
n2 = 1;
|
||||
}
|
||||
printf("%5d>%3d %d(%02x) %d(%02x) %s\n",
|
||||
notrandtab[notrandcount & 0x0f], s,
|
||||
printf("%5d > %3d %u(%02x) %u(%02x) %s\n",
|
||||
notrandtab[i], s,
|
||||
n1, (notrand() & 0xff),
|
||||
n2, (notrand() & 0xffu),
|
||||
n1 == n2 ? "=" : "!="
|
||||
);
|
||||
if (n1 != n2) err = 1;
|
||||
n1 == n2 ? "=" : "!=");
|
||||
if (n1 != n2) {
|
||||
err = 1;
|
||||
}
|
||||
notrandcount++;
|
||||
}
|
||||
}
|
134
test/val/rand.c
134
test/val/rand.c
|
@ -28,83 +28,83 @@ static uint32_t seed;
|
|||
|
||||
int ref_rand()
|
||||
{
|
||||
uint16_t output;
|
||||
/* seed follows the LCG sequence * 0x01010101 + 0xB3B3B3B3 */
|
||||
seed = seed * 0x01010101UL + 0xB3B3B3B3UL;
|
||||
/* output uses the top two bytes (reversed) XOR with bottom two bytes */
|
||||
{
|
||||
uint16_t s0 = (seed >> 0) & 0xFF;
|
||||
uint16_t s1 = (seed >> 8) & 0xFF;
|
||||
uint16_t s2 = (seed >> 16) & 0xFF;
|
||||
uint16_t s3 = (seed >> 24) & 0xFF;
|
||||
uint16_t o0 = s3 ^ s1;
|
||||
uint16_t o1 = s2 ^ s0;
|
||||
output = o0 | (o1 << 8);
|
||||
}
|
||||
return (int)(output & 0x7FFF);
|
||||
uint16_t output;
|
||||
/* seed follows the LCG sequence * 0x01010101 + 0xB3B3B3B3 */
|
||||
seed = seed * 0x01010101UL + 0xB3B3B3B3UL;
|
||||
/* output uses the top two bytes (reversed) XOR with bottom two bytes */
|
||||
{
|
||||
uint16_t s0 = (seed >> 0) & 0xFF;
|
||||
uint16_t s1 = (seed >> 8) & 0xFF;
|
||||
uint16_t s2 = (seed >> 16) & 0xFF;
|
||||
uint16_t s3 = (seed >> 24) & 0xFF;
|
||||
uint16_t o0 = s3 ^ s1;
|
||||
uint16_t o1 = s2 ^ s0;
|
||||
output = o0 | (o1 << 8);
|
||||
}
|
||||
return (int)(output & 0x7FFF);
|
||||
}
|
||||
|
||||
void ref_srand(int ax)
|
||||
{
|
||||
uint32_t s = (unsigned int)ax;
|
||||
seed = s | (s << 16); /* low 16 bits is convenient filler for high 16 bits */
|
||||
ref_rand(); /* one pre-call "shuffles" the first rand() result so it isn't too predictable */
|
||||
uint32_t s = (unsigned int)ax;
|
||||
seed = s | (s << 16); /* low 16 bits is convenient filler for high 16 bits */
|
||||
ref_rand(); /* one pre-call "shuffles" the first rand() result so it isn't too predictable */
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
unsigned int i,j;
|
||||
int a,b;
|
||||
unsigned int i,j;
|
||||
int a,b;
|
||||
|
||||
/* test that startup state is equivalent to srand(1) */
|
||||
{
|
||||
//srand(1); // implied
|
||||
ref_srand(1);
|
||||
for (j=0; j<SUBTESTS; ++j)
|
||||
{
|
||||
a = rand();
|
||||
b = ref_rand();
|
||||
if (a != b)
|
||||
{
|
||||
printf("failed startup seed at test %d. rand()=%d reference=%d\n",j,a,b);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* test that startup state is equivalent to srand(1) */
|
||||
{
|
||||
//srand(1); // implied
|
||||
ref_srand(1);
|
||||
for (j=0; j<SUBTESTS; ++j)
|
||||
{
|
||||
a = rand();
|
||||
b = ref_rand();
|
||||
if (a != b)
|
||||
{
|
||||
printf("failed startup seed at test %d. rand()=%d reference=%d\n",j,a,b);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* test every power of 2 seed */
|
||||
for (i = 0; i < 16; ++i)
|
||||
{
|
||||
srand(1<<i);
|
||||
ref_srand(1<<i);
|
||||
for (j=0; j<SUBTESTS; ++j)
|
||||
{
|
||||
a = rand();
|
||||
b = ref_rand();
|
||||
if (a != b)
|
||||
{
|
||||
printf("failed seed %d at test %d. rand()=%d reference=%d\n",(1<<i),j,a,b);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* test every power of 2 seed */
|
||||
for (i = 0; i < 16; ++i)
|
||||
{
|
||||
srand(1<<i);
|
||||
ref_srand(1<<i);
|
||||
for (j=0; j<SUBTESTS; ++j)
|
||||
{
|
||||
a = rand();
|
||||
b = ref_rand();
|
||||
if (a != b)
|
||||
{
|
||||
printf("failed seed %d at test %d. rand()=%d reference=%d\n",(1<<i),j,a,b);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* test a sampling of seeds*/
|
||||
for (i = 0; i < 32768UL; i += TESTINC)
|
||||
{
|
||||
srand(i);
|
||||
ref_srand(i);
|
||||
for (j=0; j<SUBTESTS; ++j)
|
||||
{
|
||||
a = rand();
|
||||
b = ref_rand();
|
||||
if (a != b)
|
||||
{
|
||||
printf("failed seed %d at test %d. rand()=%d reference=%d\n",(1<<i),j,a,b);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* test a sampling of seeds*/
|
||||
for (i = 0; i < 32768UL; i += TESTINC)
|
||||
{
|
||||
srand(i);
|
||||
ref_srand(i);
|
||||
for (j=0; j<SUBTESTS; ++j)
|
||||
{
|
||||
a = rand();
|
||||
b = ref_rand();
|
||||
if (a != b)
|
||||
{
|
||||
printf("failed seed %d at test %d. rand()=%d reference=%d\n",(1<<i),j,a,b);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user