Merge pull request #1 from cc65/master

Update
This commit is contained in:
polluks2
2021-01-13 12:26:00 +01:00
committed by GitHub
37 changed files with 1032 additions and 888 deletions

View File

@@ -15,6 +15,7 @@ PROMPT := $33 ; Used by GETLN
RNDL := $4E ; Random counter low RNDL := $4E ; Random counter low
RNDH := $4F ; Random counter high RNDH := $4F ; Random counter high
HIMEM := $73 ; Highest available memory address+1 HIMEM := $73 ; Highest available memory address+1
CURLIN := $75 ; Current line number being executed
;----------------------------------------------------------------------------- ;-----------------------------------------------------------------------------
; Vectors ; Vectors

View File

@@ -7,6 +7,7 @@
; Zero page, Commodore stuff ; Zero page, Commodore stuff
TXTPTR := $3D ; Pointer into BASIC source code TXTPTR := $3D ; Pointer into BASIC source code
STATUS := $90 ; Kernal I/O completion status
TIME := $A0 ; 60HZ clock TIME := $A0 ; 60HZ clock
FNAM_LEN := $B7 ; Length of filename FNAM_LEN := $B7 ; Length of filename
SECADR := $B9 ; Secondary address SECADR := $B9 ; Secondary address

View File

@@ -9,6 +9,7 @@
VARTAB := $2D ; Pointer to start of BASIC variables VARTAB := $2D ; Pointer to start of BASIC variables
MEMSIZE := $37 ; Pointer to highest BASIC RAM location (+1) MEMSIZE := $37 ; Pointer to highest BASIC RAM location (+1)
TXTPTR := $7A ; Pointer into BASIC source code TXTPTR := $7A ; Pointer into BASIC source code
STATUS := $90 ; Kernal I/O completion status
TIME := $A0 ; 60 HZ clock TIME := $A0 ; 60 HZ clock
FNAM_LEN := $B7 ; Length of filename FNAM_LEN := $B7 ; Length of filename
SECADR := $B9 ; Secondary address SECADR := $B9 ; Secondary address

View File

@@ -10,6 +10,7 @@ TMPPTR := $22 ; Temporary ptr used by BASIC
VARTAB := $2D ; Pointer to start of BASIC variables VARTAB := $2D ; Pointer to start of BASIC variables
MEMSIZE := $37 ; Pointer to highest BASIC RAM location (+1) MEMSIZE := $37 ; Pointer to highest BASIC RAM location (+1)
TXTPTR := $3B ; Pointer into BASIC source code TXTPTR := $3B ; Pointer into BASIC source code
STATUS := $90 ; Kernal I/O completion status
TIME := $A3 ; 60HZ clock TIME := $A3 ; 60HZ clock
FNAM_LEN := $AB ; Length of filename FNAM_LEN := $AB ; Length of filename
LFN := $AC ; Logical file number LFN := $AC ; Logical file number

View File

@@ -9,6 +9,7 @@
VARTAB := $2D ; Pointer to start of BASIC variables VARTAB := $2D ; Pointer to start of BASIC variables
MEMSIZE := $37 ; Pointer to highest BASIC RAM location (+1) MEMSIZE := $37 ; Pointer to highest BASIC RAM location (+1)
TXTPTR := $7A ; Pointer into BASIC source code TXTPTR := $7A ; Pointer into BASIC source code
STATUS := $90 ; Kernal I/O completion status
TIME := $A0 ; 60HZ clock TIME := $A0 ; 60HZ clock
FNAM_LEN := $B7 ; Length of filename FNAM_LEN := $B7 ; Length of filename
SECADR := $B9 ; Secondary address SECADR := $B9 ; Secondary address

View File

@@ -73,6 +73,17 @@ Special locations:
Programs containing Atari 5200 specific code may use the <tt/atari5200.h/ header file. 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> <sect1>Atari 5200 specific functions<p>

View File

@@ -6,8 +6,9 @@
<url url="mailto:gregdk@users.sf.net" name="Greg King"> <url url="mailto:gregdk@users.sf.net" name="Greg King">
<abstract> <abstract>
cc65 is a C compiler for 6502 targets. It supports several 6502 based home 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. computers such as the Commodore and Atari machines, but it easily is
retargetable.
</abstract> </abstract>
<!-- Table of contents --> <!-- Table of contents -->
@@ -548,6 +549,8 @@ Here is a description of all the command line options:
<tag><tt/remap-zero/</tag> <tag><tt/remap-zero/</tag>
Warn about a <tt/<ref id="pragma-charmap" name="#pragma charmap()">/ Warn about a <tt/<ref id="pragma-charmap" name="#pragma charmap()">/
that changes a character's code number from/to 0x00. 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> <tag><tt/struct-param/</tag>
Warn when passing structs by value. Warn when passing structs by value.
<tag><tt/unknown-pragma/</tag> <tag><tt/unknown-pragma/</tag>
@@ -706,12 +709,13 @@ This cc65 version has some extensions to the ISO C standard.
places. places.
<p> <p>
<item> There are two pseudo variables named <tt/__AX__/ and <tt/__EAX__/. <item> There are three pseudo variables named <tt/__A__/, <tt/__AX__/ and
Both refer to the primary register that is used by the compiler to <tt/__EAX__/. They all refer to the primary register that is used
evaluate expressions or return function results. <tt/__AX__/ is of by the compiler to evaluate expressions or return function results.
type <tt/unsigned int/ and <tt/__EAX__/ of type <tt/long unsigned int/ <tt/__A__/ is of type <tt/unsigned char/, <tt/__AX__/ is of type
respectively. The pseudo variables may be used as lvalue and rvalue as <tt/unsigned int/ and <tt/__EAX__/ of type <tt/long unsigned int/
every other variable. They are most useful together with short 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 sequences of assembler code. For example, the macro
<tscreen><verb> <tscreen><verb>
@@ -1045,26 +1049,39 @@ parameter with the <tt/#pragma/.
The <tt/#pragma/ understands the push and pop parameters as explained above. The <tt/#pragma/ understands the push and pop parameters as explained above.
<sect1><tt>#pragma bss-name (&lsqb;push,&rsqb; &lt;name&gt;)</tt><label id="pragma-bss-name"><p> <sect1><tt>#pragma bss-name ([push, ]&lt;name>[ ,&lt;addrsize>])</tt><label id="pragma-bss-name"><p>
This pragma changes the name used for the BSS segment (the BSS segment This pragma changes the name used for the BSS segment (the BSS segment is
is used to store variables with static storage duration and no explicit used to store variables with static storage duration and no explicit
initializer). The argument is a string enclosed in double quotes. initializers). The <tt/name/ argument is a string enclosed in quotation
marks.
Note: The default linker configuration file does only map the standard <tt/addrsize/ is an optional string that gives a hint about where the
segments. If you use other segments, you have to create a new linker <tt/name/ segment will be put in the CPU's address space. It describes the
configuration file. 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 Note: The default linker configuration file maps only the standard segments.
use another BSS segment, you have to do that yourself, otherwise If you use other segments, you must create a new linker configuration file.
variables with static storage duration and no explicit initializer will
not have the value zero.
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> <tscreen><verb>
#pragma bss-name ("MyBSS") #pragma bss-name ("MyBSS")
#pragma bss-name (push, "MyBSS")
#pragma bss-name ("MyBSS", "zp")
</verb></tscreen> </verb></tscreen>
@@ -1120,21 +1137,33 @@ parameter with the <tt/#pragma/.
The <tt/#pragma/ understands the push and pop parameters as explained above. The <tt/#pragma/ understands the push and pop parameters as explained above.
<sect1><tt>#pragma code-name ([push,] &lt;name&gt;)</tt><label id="pragma-code-name"><p> <sect1><tt>#pragma code-name ([push, ]&lt;name>[ ,&lt;addrsize>])</tt><label id="pragma-code-name"><p>
This pragma changes the name used for the CODE segment (the CODE segment This pragma changes the name used for the CODE segment (the CODE segment is
is used to store executable code). The argument is a string enclosed in used to store executable code). The <tt/name/ argument is a string enclosed
double quotes. in quotation marks.
Note: The default linker configuration file does only map the standard <tt/addrsize/ is an optional string that gives a hint about where the
segments. If you use other segments, you have to create a new linker <tt/name/ segment will be put in the CPU's address space. It describes the
configuration file. 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> <tscreen><verb>
#pragma code-name ("MyCODE") #pragma code-name ("MyCODE")
#pragma code-name (push, "MyCODE")
#pragma code-name (push, "MyCODE", "far")
</verb></tscreen> </verb></tscreen>
@@ -1148,21 +1177,33 @@ parameter with the <tt/#pragma/.
The <tt/#pragma/ understands the push and pop parameters as explained above. The <tt/#pragma/ understands the push and pop parameters as explained above.
<sect1><tt>#pragma data-name ([push,] &lt;name&gt;)</tt><label id="pragma-data-name"><p> <sect1><tt>#pragma data-name ([push, ]&lt;name>[ ,&lt;addrsize>])</tt><label id="pragma-data-name"><p>
This pragma changes the name used for the DATA segment (the DATA segment This pragma changes the name used for the DATA segment (the DATA segment is
is used to store initialized data). The argument is a string enclosed in used to store initialized data). The <tt/name/ argument is a string enclosed
double quotes. in quotation marks.
Note: The default linker configuration file does only map the standard <tt/addrsize/ is an optional string that gives a hint about where the
segments. If you use other segments, you have to create a new linker <tt/name/ segment will be put in the CPU's address space. It describes the
configuration file. 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> <tscreen><verb>
#pragma data-name ("MyDATA") #pragma data-name ("MyDATA")
#pragma data-name (push, "MyDATA")
#pragma data-name ("MyDATA", "zeropage")
</verb></tscreen> </verb></tscreen>
@@ -1224,21 +1265,32 @@ parameter with the <tt/#pragma/.
The <tt/#pragma/ understands the push and pop parameters as explained above. The <tt/#pragma/ understands the push and pop parameters as explained above.
<sect1><tt>#pragma rodata-name ([push,] &lt;name&gt;)</tt><label id="pragma-rodata-name"><p> <sect1><tt>#pragma rodata-name ([push, ]&lt;name>[ ,&lt;addrsize>])</tt><label id="pragma-rodata-name"><p>
This pragma changes the name used for the RODATA segment (the RODATA This pragma changes the name used for the RODATA segment (the RODATA segment
segment is used to store readonly data). The argument is a string is used to store read-only data). The <tt/name/ argument is a string enclosed
enclosed in double quotes. in quotation marks.
Note: The default linker configuration file does only map the standard <tt/addrsize/ is an optional string that gives a hint about where the
segments. If you use other segments, you have to create a new linker <tt/name/ segment will be put in the CPU's address space. It describes the
configuration file. 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> <tscreen><verb>
#pragma rodata-name ("MyRODATA") #pragma rodata-name ("MyRODATA")
#pragma rodata-name (push, "MyRODATA")
</verb></tscreen> </verb></tscreen>

80
include/_atari5200os.h Normal file
View 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

View File

@@ -65,6 +65,10 @@ extern void atr5200std_joy[]; /* referred to by joy_static_stddrv[] */
#define AT_NTSC 0 #define AT_NTSC 0
#define AT_PAL 1 #define AT_PAL 1
/* Define variables used by the OS*/
#include <_atari5200os.h>
#define OS (*(struct __os*)0x0000)
/* define hardware */ /* define hardware */
#include <_gtia.h> #include <_gtia.h>
#define GTIA_READ (*(struct __gtia_read*)0xC000) #define GTIA_READ (*(struct __gtia_read*)0xC000)

View File

@@ -19,11 +19,14 @@
.segment "ONCE" .segment "ONCE"
initprompt: initprompt:
; Set prompt <> ']' to let DOS 3.3 know that we're ; Set prompt <> ']' and currently executed Applesoft
; not in Applesoft immediate mode and thus keep it ; line number hibyte <> $FF to let DOS 3.3 (at $A65E)
; from scanning our device I/O for DOS commands. ; 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 lda #$80 ; Same value used at $D52C
sta PROMPT sta PROMPT
sta CURLIN+1 ; Any value <> $FF will do
rts rts
.code .code

View File

@@ -20,18 +20,19 @@
sta ptr3 sta ptr3
stx ptr3+1 ; save count as result stx ptr3+1 ; save count as result
eor #$FF
sta ptr2 inx
txa stx ptr2+1
eor #$FF tax
sta ptr2+1 ; Remember -count-1 inx
stx ptr2 ; save count with each byte incremented separately
jsr popptr1 ; get buf jsr popptr1 ; get buf
jsr popax ; get fd and discard jsr popax ; get fd and discard
L1: inc ptr2 L1: dec ptr2
bnz L2 bnz L2
inc ptr2+1 dec ptr2+1
bze L9 ; no more room in buf bze L9 ; no more room in buf
; If there are no more characters in BASIC's input buffer, then get a line from ; If there are no more characters in BASIC's input buffer, then get a line from

View File

@@ -17,17 +17,17 @@
sta ptr3 sta ptr3
stx ptr3+1 ; save count as result stx ptr3+1 ; save count as result
eor #$FF inx
sta ptr2 stx ptr2+1
txa tax
eor #$FF inx
sta ptr2+1 ; Remember -count-1 stx ptr2 ; save count with each byte incremented separately
jsr popptr1 ; get buf jsr popptr1 ; get buf
jsr popax ; get fd and discard jsr popax ; get fd and discard
L1: inc ptr2 L1: dec ptr2
bne L2 bne L2
inc ptr2+1 dec ptr2+1
beq L9 beq L9
L2: ldy #0 L2: ldy #0
lda (ptr1),y lda (ptr1),y

View File

@@ -45,11 +45,11 @@
_cbm_read: _cbm_read:
eor #$FF inx
sta ptr1 stx ptr1+1
txa tax
eor #$FF inx
sta ptr1+1 ; Save -size-1 stx ptr1 ; Save size with both bytes incremented separately.
jsr popax jsr popax
sta ptr2 sta ptr2
@@ -92,9 +92,9 @@ _cbm_read:
bne @L3 bne @L3
inc ptr3+1 ; ++bytesread; inc ptr3+1 ; ++bytesread;
@L3: inc ptr1 @L3: dec ptr1
bne @L1 bne @L1
inc ptr1+1 dec ptr1+1
bne @L1 bne @L1
@L4: jsr CLRCH @L4: jsr CLRCH

View File

@@ -39,11 +39,11 @@
_cbm_write: _cbm_write:
sta ptr3 sta ptr3
stx ptr3+1 ; Save size stx ptr3+1 ; Save size
eor #$FF inx
sta ptr1 stx ptr1+1
txa tax
eor #$FF inx
sta ptr1+1 ; Save -size-1 stx ptr1 ; Save size with both bytes incremented separately
jsr popax jsr popax
sta ptr2 sta ptr2
@@ -69,9 +69,9 @@ _cbm_write:
@L2: jsr BSOUT ; cbm_k_bsout (A); @L2: jsr BSOUT ; cbm_k_bsout (A);
@L3: inc ptr1 ; --size; @L3: dec ptr1 ; --size;
bne @L1 bne @L1
inc ptr1+1 dec ptr1+1
bne @L1 bne @L1
jsr CLRCH jsr CLRCH

View File

@@ -106,9 +106,9 @@
; Decrement the count ; Decrement the count
@L3: inc ptr2 @L3: dec ptr2
bne @L0 bne @L0
inc ptr2+1 dec ptr2+1
bne @L0 bne @L0
beq done ; Branch always beq done ; Branch always

View File

@@ -21,11 +21,11 @@
.proc rwcommon .proc rwcommon
eor #$FF inx
sta ptr2 stx ptr2+1
txa tax
eor #$FF inx
sta ptr2+1 ; Remember -count-1 stx ptr2 ; Save count with each byte incremented separately
jsr popptr1 ; Get buf to ptr1, Y=0 by call jsr popptr1 ; Get buf to ptr1, Y=0 by call

View File

@@ -83,9 +83,9 @@
; Decrement count ; Decrement count
@L2: inc ptr2 @L2: dec ptr2
bne @L0 bne @L0
inc ptr2+1 dec ptr2+1
bne @L0 bne @L0
; Wrote all chars or disk full. Close the output channel ; Wrote all chars or disk full. Close the output channel

View File

@@ -17,22 +17,22 @@
.proc _getcwd .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 inx
sta ptr2 stx ptr2+1
txa tax
eor #$FF inx
sta ptr2+1 stx ptr2 ; Save size with each byte incremented separately
jsr popptr1 ; Get buf to ptr1 jsr popptr1 ; Get buf to ptr1
; Copy __cwd to the given buffer checking the length ; Copy __cwd to the given buffer checking the length
; ldy #$00 is guaranteed by popptr1 ; ldy #$00 is guaranteed by popptr1
loop: inc ptr2 loop: dec ptr2
bne @L1 bne @L1
inc ptr2+1 dec ptr2+1
beq overflow beq overflow
; Copy one character, end the loop if the zero terminator is reached. We ; Copy one character, end the loop if the zero terminator is reached. We

View File

@@ -10,14 +10,14 @@
_memcmp: _memcmp:
; Calculate (-count-1) and store it into ptr3. This is some overhead here but ; Calculate a special count, and store it into ptr3. That is some overhead here,
; saves time in the compare loop ; but saves time in the compare loop
eor #$FF inx
sta ptr3 stx ptr3+1
txa tax
eor #$FF inx
sta ptr3+1 stx ptr3 ; Save count with each byte incremented separately
; Get the pointer parameters ; Get the pointer parameters
@@ -29,12 +29,12 @@ _memcmp:
; Loop initialization ; Loop initialization
;ldy #$00 ; Initialize pointer (Y=0 guaranteed by popptr1) ;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 ; Head of compare loop: Test for the end condition
Loop: inx ; Bump low byte of (-count-1) Loop: dex
beq BumpHiCnt ; Jump on overflow beq BumpHiCnt ; Jump on end of inner count
; Do the compare ; Do the compare
@@ -50,10 +50,10 @@ Comp: lda (ptr1),y
inc ptr2+1 inc ptr2+1
bne Loop ; Branch always (pointer wrap is illegal) bne Loop ; Branch always (pointer wrap is illegal)
; Entry on low counter byte overflow ; Entry on inner loop end
BumpHiCnt: BumpHiCnt:
inc ptr3+1 ; Bump high byte of (-count-1) dec ptr3+1
bne Comp ; Jump if not done bne Comp ; Jump if not done
jmp return0 ; Count is zero, areas are identical jmp return0 ; Count is zero, areas are identical
@@ -67,4 +67,3 @@ NotEqual:
Greater: Greater:
ldx #$01 ; Make result positive ldx #$01 ; Make result positive
rts rts

View File

@@ -5,17 +5,17 @@
; char* strncat (char* dest, const char* src, size_t n); ; char* strncat (char* dest, const char* src, size_t n);
; ;
.export _strncat .export _strncat
.import popax, popptr1 .import popax, popptr1
.importzp ptr1, ptr2, ptr3, tmp1, tmp2 .importzp ptr1, ptr2, ptr3, tmp1, tmp2
.macpack cpu .macpack cpu
_strncat: _strncat:
eor #$FF ; one's complement to count upwards inx
sta tmp1 stx tmp2
txa tax
eor #$FF inx
sta tmp2 stx tmp1 ; save count with each byte incremented separately
jsr popptr1 ; get src jsr popptr1 ; get src
@@ -49,9 +49,9 @@ L2: sty ptr2
L3: ldy #0 L3: ldy #0
ldx tmp1 ; low counter byte ldx tmp1 ; low counter byte
L4: inx L4: dex
bne L5 bne L5
inc tmp2 dec tmp2
beq L6 ; jump if done beq L6 ; jump if done
L5: lda (ptr1),y L5: lda (ptr1),y
sta (ptr2),y sta (ptr2),y

View File

@@ -10,11 +10,11 @@
.proc _strncpy .proc _strncpy
eor #$FF inx
sta tmp1 stx tmp2
txa tax
eor #$FF inx
sta tmp2 ; Store -size - 1 stx tmp1 ; save count with each byte incremented separately
jsr popptr1 ; get src jsr popptr1 ; get src
jsr popax ; get dest jsr popax ; get dest
@@ -24,11 +24,11 @@
; Copy src -> dest up to size bytes ; Copy src -> dest up to size bytes
ldx tmp1 ; Load low byte of ones complement of size ldx tmp1
ldy #$00 ldy #$00
L1: inx L1: dex
bne L2 bne L2
inc tmp2 dec tmp2
beq L9 beq L9
L2: lda (ptr1),y ; Copy one character L2: lda (ptr1),y ; Copy one character
@@ -42,8 +42,8 @@ L2: lda (ptr1),y ; Copy one character
; Fill the remaining bytes. ; Fill the remaining bytes.
L3: inx ; Counter low byte L3: dex ; Counter low byte
beq L6 ; Branch on overflow beq L6
L4: sta (ptr2),y ; Clear one byte L4: sta (ptr2),y ; Clear one byte
L5: iny ; Bump pointer L5: iny ; Bump pointer
bne L3 bne L3
@@ -52,7 +52,7 @@ L5: iny ; Bump pointer
; Bump the counter high byte ; Bump the counter high byte
L6: inc tmp2 L6: dec tmp2
bne L4 bne L4
; Done, return dest ; Done, return dest

View File

@@ -15,17 +15,11 @@
_strnicmp: _strnicmp:
_strncasecmp: _strncasecmp:
; Convert the given counter value in a/x from a downward counter into an inx
; upward counter, so we can increment the counter in the loop below instead stx ptr3+1
; of decrementing it. This adds some overhead now, but is cheaper than tax
; executing a more complex test in each iteration of the loop. We do also inx
; correct the value by one, so we can do the test on top of the loop. stx ptr3 ; save count with each byte incremented separately
eor #$FF
sta ptr3
txa
eor #$FF
sta ptr3+1
; Get the remaining arguments ; Get the remaining arguments
@@ -40,8 +34,8 @@ _strncasecmp:
; Start of compare loop. Check the counter. ; Start of compare loop. Check the counter.
Loop: inc ptr3 Loop: dec ptr3 ; decrement high byte
beq IncHi ; increment high byte beq IncHi
; Compare a byte from the strings ; Compare a byte from the strings
@@ -79,7 +73,7 @@ L2: ldx tmp1
; Increment hi byte ; Increment hi byte
IncHi: inc ptr3+1 IncHi: dec ptr3+1
bne Comp ; jump if counter not zero bne Comp ; jump if counter not zero
; Exit code if strings are equal. a/x not set ; Exit code if strings are equal. a/x not set

View File

@@ -47,12 +47,12 @@ outdesc: ; Static outdesc structure
out: jsr popax ; count out: jsr popax ; count
sta ptr2 sta ptr2
eor #$FF stx ptr2+1
sta outdesc+6 inx
txa stx outdesc+7
sta ptr2+1 tax
eor #$FF inx
sta outdesc+7 stx outdesc+6
jsr popptr1 ; buf jsr popptr1 ; buf
@@ -74,7 +74,7 @@ out: jsr popax ; count
; Loop outputting characters ; Loop outputting characters
@L1: inc outdesc+6 @L1: dec outdesc+6
beq @L4 beq @L4
@L2: ldy tmp1 @L2: ldy tmp1
lda (ptr1),y lda (ptr1),y
@@ -85,7 +85,7 @@ out: jsr popax ; count
jsr _cputc jsr _cputc
jmp @L1 jmp @L1
@L4: inc outdesc+7 @L4: dec outdesc+7
bne @L2 bne @L2
rts rts

View File

@@ -94,11 +94,12 @@ _read:
; popax - fd, must be == to the above one ; popax - fd, must be == to the above one
; return -1+__oserror or number of bytes read ; return -1+__oserror or number of bytes read
eor #$ff inx
sta ptr1 stx ptr1+1
txa tax
eor #$ff inx
sta ptr1+1 ; -(# of bytes to read)-1 stx ptr1 ; save count with each byte incremented separately
jsr popax jsr popax
sta ptr2 sta ptr2
stx ptr2+1 ; buffer ptr stx ptr2+1 ; buffer ptr
@@ -152,9 +153,9 @@ _read:
beq @done ; yes, we're done beq @done ; yes, we're done
jmp __mappederrno ; no, we're screwed jmp __mappederrno ; no, we're screwed
@L3: inc ptr1 ; decrement the count @L3: dec ptr1 ; decrement the count
bne @L0 bne @L0
inc ptr1+1 dec ptr1+1
bne @L0 bne @L0
@done: @done:

View File

@@ -50,16 +50,15 @@ LINEDIST = $20 ; Offset in video RAM between two lines
ldx #>load_addr ldx #>load_addr
sta load sta load
stx load+1 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 bnz L2
inc count+1 dec count+1
bze L3 bze L3
L2: jsr GETCHAR ; (doesn't change .Y) L2: jsr GETCHAR ; (doesn't change .Y)
sta (load),y sta (load),y

View File

@@ -13,11 +13,11 @@
sta ptr3 sta ptr3
stx ptr3+1 ; save count as result stx ptr3+1 ; save count as result
eor #$FF inx
sta ptr2 stx ptr2+1
txa tax
eor #$FF inx
sta ptr2+1 ; remember -count-1 stx ptr2 ; save count with each byte incremented separately
jsr popptr1 ; get buf jsr popptr1 ; get buf
jsr popax ; get fd and discard jsr popax ; get fd and discard
@@ -51,9 +51,9 @@ next:
rts rts
L1: inc ptr2 L1: dec ptr2
bne L2 bne L2
inc ptr2+1 dec ptr2+1
beq L9 beq L9
L2: ldy #0 L2: ldy #0
lda (ptr1),y lda (ptr1),y

View File

@@ -1433,17 +1433,20 @@ unsigned g_typeadjust (unsigned lhs, unsigned rhs)
/* Note that this logic is largely duplicated by ArithmeticConvert. */ /* Note that this logic is largely duplicated by ArithmeticConvert. */
/* Before we apply the integral promotions, we check if both types are unsigned char. /* Before we apply the integral promotions, we check if both types are the same character type.
** If so, we return unsigned int, rather than int, which would be returned by the standard ** If so, we return that type, rather than int, which would be returned by the standard
** rules. This is only a performance optimization and does not affect correctness, as ** rules. This is only a performance optimization allowing the use of unsigned and/or char
** the flags are only used for code generation, and not to determine types of other ** operations; it does not affect correctness, as the flags are only used for code generation,
** expressions containing this one. All unsigned char bit-patterns are valid as both int ** and not to determine types of other expressions containing this one. For codgen, CF_CHAR
** and unsigned int and represent the same value, so either signed or unsigned int operations ** means the operands are char and the result is int (unless CF_FORCECHAR is also set, in
** can be used. This special case part is not duplicated by ArithmeticConvert. ** which case the result is char). This special case part is not duplicated by
** ArithmeticConvert.
*/ */
if ((lhs & CF_TYPEMASK) == CF_CHAR && (lhs & CF_UNSIGNED) && if ((lhs & CF_TYPEMASK) == CF_CHAR && (rhs & CF_TYPEMASK) == CF_CHAR &&
(rhs & CF_TYPEMASK) == CF_CHAR && (rhs & CF_UNSIGNED)) { (lhs & CF_UNSIGNED) == (rhs & CF_UNSIGNED)) {
return const_flag | CF_UNSIGNED | CF_INT; /* 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. */ /* Apply integral promotions for types char/short. */
@@ -3111,9 +3114,26 @@ void g_asr (unsigned flags, unsigned long val)
switch (flags & CF_TYPEMASK) { switch (flags & CF_TYPEMASK) {
case CF_CHAR: case CF_CHAR:
if (flags & CF_FORCECHAR) { if (flags & CF_FORCECHAR) {
if ((flags & CF_UNSIGNED) != 0 && val < 8) { val &= 7;
while (val--) { if ((flags & CF_UNSIGNED) != 0) {
AddCodeLine ("lsr a"); /* 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; return;
} else if (val <= 2) { } else if (val <= 2) {
@@ -3267,9 +3287,21 @@ void g_asl (unsigned flags, unsigned long val)
if (flags & CF_CONST) { if (flags & CF_CONST) {
switch (flags & CF_TYPEMASK) { switch (flags & CF_TYPEMASK) {
case CF_CHAR: case CF_CHAR:
if ((flags & CF_FORCECHAR) != 0 && val <= 6) { if ((flags & CF_FORCECHAR) != 0) {
while (val--) { val &= 7;
AddCodeLine ("asl a"); /* 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; return;
} }

View File

@@ -1100,7 +1100,7 @@ static unsigned Opt_tosxorax (StackOpData* D)
static unsigned Opt_a_toscmpbool (StackOpData* D, const char* BoolTransformer) 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; CodeEntry* X;
cmp_t Cond; cmp_t Cond;
@@ -1119,9 +1119,8 @@ static unsigned Opt_a_toscmpbool (StackOpData* D, const char* BoolTransformer)
D->Rhs.A.Flags |= LI_REMOVE; D->Rhs.A.Flags |= LI_REMOVE;
} else if ((D->Lhs.A.Flags & LI_DIRECT) != 0) { } else if ((D->Lhs.A.Flags & LI_DIRECT) != 0) {
/* If the lhs is direct (but not stack relative), encode compares with lhs,
/* If the lhs is direct (but not stack relative), encode compares with lhs ** effectively reversing the order (which doesn't matter for == and !=).
** effectively reverting the order (which doesn't matter for ==).
*/ */
Cond = FindBoolCmpCond (BoolTransformer); Cond = FindBoolCmpCond (BoolTransformer);
Cond = GetRevertedCond (Cond); Cond = GetRevertedCond (Cond);
@@ -1138,7 +1137,6 @@ static unsigned Opt_a_toscmpbool (StackOpData* D, const char* BoolTransformer)
D->Lhs.A.Flags |= LI_REMOVE; D->Lhs.A.Flags |= LI_REMOVE;
} else { } else {
/* We'll do reverse-compare */ /* We'll do reverse-compare */
Cond = FindBoolCmpCond (BoolTransformer); Cond = FindBoolCmpCond (BoolTransformer);
Cond = GetRevertedCond (Cond); 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); X = NewCodeEntry (OP65_JSR, AM65_ABS, BoolTransformer, 0, D->OpEntry->LI);
InsertEntry (D, X, D->IP++); 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); RemoveRemainders (D);
/* We changed the sequence */ /* 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) static unsigned Opt_a_tosicmp (StackOpData* D)
/* Replace tosicmp with CMP */ /* Replace tosicmp with CMP */
{ {
@@ -1236,7 +1218,7 @@ static unsigned Opt_a_tosicmp (StackOpData* D)
} }
InsertEntry (D, X, D->IP++); 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) { if (D->Rhs.A.LoadEntry->OPC == OP65_JSR) {
/* opc (sp),y */ /* opc (sp),y */
X = NewCodeEntry (OP65_CMP, AM65_ZP_INDY, "sp", 0, D->OpEntry->LI); 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); InsertEntry (D, X, D->IP-3);
} else { } 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 && if ((RI = GetLastChangedRegInfo (D, &D->Lhs.A)) != 0 &&
RegValIsKnown (RI->Out.RegA) && RegValIsKnown (RI->Out.RegA) &&
(RI->Out.RegA & 0xFF) == 0) { (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); InsertEntry (D, X, D->OpIndex + 1);
} else { } 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); 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); 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) static unsigned Opt_a_tosne (StackOpData* D)
/* Optimize the toseqax sequence */ /* Optimize the tosneax sequence */
{ {
return Opt_a_toscmpbool (D, "boolne"); return Opt_a_toscmpbool (D, "boolne");
} }
@@ -1317,7 +1283,7 @@ static unsigned Opt_a_tosne (StackOpData* D)
static unsigned Opt_a_tosuge (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"); return Opt_a_toscmpbool (D, "booluge");
} }
@@ -1325,7 +1291,7 @@ static unsigned Opt_a_tosuge (StackOpData* D)
static unsigned Opt_a_tosugt (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"); return Opt_a_toscmpbool (D, "boolugt");
} }
@@ -1333,7 +1299,7 @@ static unsigned Opt_a_tosugt (StackOpData* D)
static unsigned Opt_a_tosule (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"); return Opt_a_toscmpbool (D, "boolule");
} }
@@ -1341,7 +1307,7 @@ static unsigned Opt_a_tosule (StackOpData* D)
static unsigned Opt_a_tosult (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"); 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[] = { static const OptFuncDesc FuncTable[] = {
{ "__bzero", Opt___bzero, REG_NONE, OP_X_ZERO | OP_A_KNOWN }, { "__bzero", Opt___bzero, REG_NONE, OP_X_ZERO | OP_A_KNOWN },
{ "staspidx", Opt_staspidx, REG_NONE, OP_NONE }, { "staspidx", Opt_staspidx, REG_NONE, OP_NONE },
@@ -1379,11 +1347,11 @@ static const OptFuncDesc FuncTable[] = {
static const OptFuncDesc FuncRegATable[] = { static const OptFuncDesc FuncRegATable[] = {
{ "toseqax", Opt_a_toseq, REG_NONE, OP_NONE }, { "toseqax", Opt_a_toseq, REG_NONE, OP_NONE },
{ "tosgeax", Opt_a_tosge, REG_NONE, OP_NONE }, { "tosgeax", Opt_a_tosuge, REG_NONE, OP_NONE },
{ "tosgtax", Opt_a_tosgt, REG_NONE, OP_NONE }, { "tosgtax", Opt_a_tosugt, REG_NONE, OP_NONE },
{ "tosicmp", Opt_a_tosicmp, REG_NONE, OP_NONE }, { "tosicmp", Opt_a_tosicmp, REG_NONE, OP_NONE },
{ "tosleax", Opt_a_tosle, REG_NONE, OP_NONE }, { "tosleax", Opt_a_tosule, REG_NONE, OP_NONE },
{ "tosltax", Opt_a_toslt, REG_NONE, OP_NONE }, { "tosltax", Opt_a_tosult, REG_NONE, OP_NONE },
{ "tosneax", Opt_a_tosne, REG_NONE, OP_NONE }, { "tosneax", Opt_a_tosne, REG_NONE, OP_NONE },
{ "tosugeax", Opt_a_tosuge, REG_NONE, OP_NONE }, { "tosugeax", Opt_a_tosuge, REG_NONE, OP_NONE },
{ "tosugtax", Opt_a_tosugt, REG_NONE, OP_NONE }, { "tosugtax", Opt_a_tosugt, REG_NONE, OP_NONE },

View File

@@ -74,6 +74,7 @@ IntStack WarnUnknownPragma = INTSTACK(1); /* - unknown #pragmas */
IntStack WarnUnusedLabel = INTSTACK(1); /* - unused labels */ IntStack WarnUnusedLabel = INTSTACK(1); /* - unused labels */
IntStack WarnUnusedParam = INTSTACK(1); /* - unused parameters */ IntStack WarnUnusedParam = INTSTACK(1); /* - unused parameters */
IntStack WarnUnusedVar = INTSTACK(1); /* - unused variables */ 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 */ /* Map the name of a warning to the intstack that holds its state */
typedef struct WarnMapEntry WarnMapEntry; typedef struct WarnMapEntry WarnMapEntry;
@@ -92,6 +93,7 @@ static WarnMapEntry WarnMap[] = {
{ &WarnUnusedLabel, "unused-label" }, { &WarnUnusedLabel, "unused-label" },
{ &WarnUnusedParam, "unused-param" }, { &WarnUnusedParam, "unused-param" },
{ &WarnUnusedVar, "unused-var" }, { &WarnUnusedVar, "unused-var" },
{ &WarnReturnType, "return-type" },
}; };
Collection DiagnosticStrBufs; Collection DiagnosticStrBufs;

View File

@@ -71,6 +71,7 @@ extern IntStack WarnUnknownPragma; /* - unknown #pragmas */
extern IntStack WarnUnusedLabel; /* - unused labels */ extern IntStack WarnUnusedLabel; /* - unused labels */
extern IntStack WarnUnusedParam; /* - unused parameters */ extern IntStack WarnUnusedParam; /* - unused parameters */
extern IntStack WarnUnusedVar; /* - unused variables */ extern IntStack WarnUnusedVar; /* - unused variables */
extern IntStack WarnReturnType; /* - control reaches end of non-void function */
/* Forward */ /* Forward */
struct StrBuf; struct StrBuf;

View File

@@ -23,10 +23,10 @@
#define SQP_KEEP_NONE 0x00 #define SQP_KEEP_NONE 0x00
#define SQP_KEEP_TEST 0x01U #define SQP_KEEP_TEST 0x01U
#define SQP_KEEP_EAX 0x02U #define SQP_KEEP_EAX 0x02U
#define SQP_KEEP_EXPR 0x03U /* SQP_KEEP_TEST | SQP_KEEP_EAX */ #define SQP_KEEP_EXPR 0x03U /* SQP_KEEP_TEST | SQP_KEEP_EAX */

View File

@@ -654,8 +654,8 @@ void NewFunc (SymEntry* Func, FuncDesc* D)
** environment returning int, output a warning if we didn't see a return ** environment returning int, output a warning if we didn't see a return
** statement. ** statement.
*/ */
if (!F_HasVoidReturn (CurrentFunc) && !F_HasReturn (CurrentFunc) && !C99MainFunc) { if (!F_HasVoidReturn (CurrentFunc) && !F_HasReturn (CurrentFunc) && !C99MainFunc && IS_Get (&WarnReturnType)) {
Warning ("Control reaches end of non-void function"); Warning ("Control reaches end of non-void function [-Wreturn-type]");
} }
/* If this is the main function in a C99 environment returning an int, let /* If this is the main function in a C99 environment returning an int, let

View File

@@ -117,14 +117,6 @@ $(WORKDIR)/endless.$1.$2.prg: endless.c | $(WORKDIR)
$(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) $(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, # these need reference data that can't be generated by a host-compiled program,
# in a useful way # in a useful way
$(WORKDIR)/limits.$1.$2.prg: limits.c $(ISEQUAL) | $(WORKDIR) $(WORKDIR)/limits.$1.$2.prg: limits.c $(ISEQUAL) | $(WORKDIR)

File diff suppressed because it is too large Load Diff

View File

@@ -7,24 +7,24 @@
struct ImageStruct struct ImageStruct
{ {
uint8_t _imageData; uint8_t _imageData;
#if !defined(NO_COLOR) #if !defined(NO_COLOR)
uint8_t _color; uint8_t _color;
#endif #endif
}; };
typedef struct ImageStruct Image; typedef struct ImageStruct Image;
struct CharacterStruct struct CharacterStruct
{ {
// character coordinates // character coordinates
uint8_t _x; uint8_t _x;
uint8_t _y; uint8_t _y;
// _status decides whether the character is active // _status decides whether the character is active
uint8_t _status; uint8_t _status;
Image* _imagePtr; Image* _imagePtr;
}; };
typedef struct CharacterStruct Character; typedef struct CharacterStruct Character;
@@ -53,20 +53,20 @@ Character bombs[BOMBS_NUMBER];
uint16_t test1(void) uint16_t test1(void)
{ {
if((loop<MAX_GHOST_LOOP) && (ghostLevel<MAX_GHOST_LEVEL)) if((loop<MAX_GHOST_LOOP) && (ghostLevel<MAX_GHOST_LEVEL))
{ {
return INITIAL_GHOST_SLOWDOWN-(uint16_t)level*256-ghostLevel*8; return INITIAL_GHOST_SLOWDOWN-(uint16_t)level*256-ghostLevel*8;
} }
return GHOST_MIN_SLOWDOWN; return GHOST_MIN_SLOWDOWN;
} }
uint16_t test2(void) uint16_t test2(void)
{ {
if((loop<MAX_GHOST_LOOP) && (ghostLevel<MAX_GHOST_LEVEL)) if((loop<MAX_GHOST_LOOP) && (ghostLevel<MAX_GHOST_LEVEL))
{ {
return INITIAL_GHOST_SLOWDOWN-(uint16_t)level*256-ghostLevel*16; return INITIAL_GHOST_SLOWDOWN-(uint16_t)level*256-ghostLevel*16;
} }
return GHOST_MIN_SLOWDOWN; return GHOST_MIN_SLOWDOWN;
} }
uint16_t res = 0; uint16_t res = 0;

View File

@@ -1,27 +1,26 @@
/* bug #1348, wrongly optimized integer promotion in comparison */
/* bug#1348, wrongly optimized integer promotion in comparison */
#include <stdio.h> #include <stdio.h>
int notrandtab[] = { static const int notrandtab[] = {
0xffff, 0x7fff, 0x3fff, 0x1fff, 0xffff, 0x7fff, 0x3fff, 0x1fff,
0x0fff, 0x07ff, 0x03ff, 0x01ff, 0x0fff, 0x07ff, 0x03ff, 0x01ff,
0x00ff, 0x007f, 0x003f, 0x001f, 0x00ff, 0x007f, 0x003f, 0x001f,
0x000f, 0x0007, 0x0003, 0x0001 0x000f, 0x0007, 0x0003, 0x0001
}; };
unsigned char notrandcount = 0; static unsigned char notrandcount = 0;
int notrand(void) static int notrand(void)
{ {
return notrandtab[notrandcount & 0x0f]; return notrandtab[notrandcount & 0x0f];
} }
unsigned char n1, n2; static unsigned char n1, n2;
unsigned char i, ii, s; static unsigned char i, ii, s;
unsigned char err = 0; static unsigned char err = 0;
unsigned char cmptab[] = { static const unsigned char cmptab[] = {
0xff, 0x7f, 0x3f, 0x1f, 0xff, 0x7f, 0x3f, 0x1f,
0x0f, 0x07, 0x03, 0x01, 0x0f, 0x07, 0x03, 0x01,
0x80, 0x40, 0x20, 0x10, 0x80, 0x40, 0x20, 0x10,
@@ -40,13 +39,14 @@ int main(void)
if ((notrand() & 0xffu) > s) { if ((notrand() & 0xffu) > s) {
n2 = 1; n2 = 1;
} }
printf("%5d>%3d %d(%02x) %d(%02x) %s\n", printf("%5d > %3d %u(%02x) %u(%02x) %s\n",
notrandtab[notrandcount & 0x0f], s, notrandtab[i], s,
n1, (notrand() & 0xff), n1, (notrand() & 0xff),
n2, (notrand() & 0xffu), n2, (notrand() & 0xffu),
n1 == n2 ? "=" : "!=" n1 == n2 ? "=" : "!=");
); if (n1 != n2) {
if (n1 != n2) err = 1; err = 1;
}
notrandcount++; notrandcount++;
} }
} }

View File

@@ -28,83 +28,83 @@ static uint32_t seed;
int ref_rand() int ref_rand()
{ {
uint16_t output; uint16_t output;
/* seed follows the LCG sequence * 0x01010101 + 0xB3B3B3B3 */ /* seed follows the LCG sequence * 0x01010101 + 0xB3B3B3B3 */
seed = seed * 0x01010101UL + 0xB3B3B3B3UL; seed = seed * 0x01010101UL + 0xB3B3B3B3UL;
/* output uses the top two bytes (reversed) XOR with bottom two bytes */ /* output uses the top two bytes (reversed) XOR with bottom two bytes */
{ {
uint16_t s0 = (seed >> 0) & 0xFF; uint16_t s0 = (seed >> 0) & 0xFF;
uint16_t s1 = (seed >> 8) & 0xFF; uint16_t s1 = (seed >> 8) & 0xFF;
uint16_t s2 = (seed >> 16) & 0xFF; uint16_t s2 = (seed >> 16) & 0xFF;
uint16_t s3 = (seed >> 24) & 0xFF; uint16_t s3 = (seed >> 24) & 0xFF;
uint16_t o0 = s3 ^ s1; uint16_t o0 = s3 ^ s1;
uint16_t o1 = s2 ^ s0; uint16_t o1 = s2 ^ s0;
output = o0 | (o1 << 8); output = o0 | (o1 << 8);
} }
return (int)(output & 0x7FFF); return (int)(output & 0x7FFF);
} }
void ref_srand(int ax) void ref_srand(int ax)
{ {
uint32_t s = (unsigned int)ax; uint32_t s = (unsigned int)ax;
seed = s | (s << 16); /* low 16 bits is convenient filler for high 16 bits */ 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 */ ref_rand(); /* one pre-call "shuffles" the first rand() result so it isn't too predictable */
} }
int main(void) int main(void)
{ {
unsigned int i,j; unsigned int i,j;
int a,b; int a,b;
/* test that startup state is equivalent to srand(1) */ /* test that startup state is equivalent to srand(1) */
{ {
//srand(1); // implied //srand(1); // implied
ref_srand(1); ref_srand(1);
for (j=0; j<SUBTESTS; ++j) for (j=0; j<SUBTESTS; ++j)
{ {
a = rand(); a = rand();
b = ref_rand(); b = ref_rand();
if (a != b) if (a != b)
{ {
printf("failed startup seed at test %d. rand()=%d reference=%d\n",j,a,b); printf("failed startup seed at test %d. rand()=%d reference=%d\n",j,a,b);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
} }
} }
/* test every power of 2 seed */ /* test every power of 2 seed */
for (i = 0; i < 16; ++i) for (i = 0; i < 16; ++i)
{ {
srand(1<<i); srand(1<<i);
ref_srand(1<<i); ref_srand(1<<i);
for (j=0; j<SUBTESTS; ++j) for (j=0; j<SUBTESTS; ++j)
{ {
a = rand(); a = rand();
b = ref_rand(); b = ref_rand();
if (a != b) if (a != b)
{ {
printf("failed seed %d at test %d. rand()=%d reference=%d\n",(1<<i),j,a,b); printf("failed seed %d at test %d. rand()=%d reference=%d\n",(1<<i),j,a,b);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
} }
} }
/* test a sampling of seeds*/ /* test a sampling of seeds*/
for (i = 0; i < 32768UL; i += TESTINC) for (i = 0; i < 32768UL; i += TESTINC)
{ {
srand(i); srand(i);
ref_srand(i); ref_srand(i);
for (j=0; j<SUBTESTS; ++j) for (j=0; j<SUBTESTS; ++j)
{ {
a = rand(); a = rand();
b = ref_rand(); b = ref_rand();
if (a != b) if (a != b)
{ {
printf("failed seed %d at test %d. rand()=%d reference=%d\n",(1<<i),j,a,b); printf("failed seed %d at test %d. rand()=%d reference=%d\n",(1<<i),j,a,b);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
} }
} }
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }