1
0
mirror of https://github.com/cc65/cc65.git synced 2024-12-23 19:29:37 +00:00

Merge remote-tracking branch 'upstream/master'

This commit is contained in:
mrdudz 2022-04-19 14:49:51 +02:00
commit e2ad9efe41
580 changed files with 6366 additions and 2610 deletions

13
.github/checks/Makefile vendored Normal file
View File

@ -0,0 +1,13 @@
.PHONY: check tabs lastline spaces
check: tabs lastline spaces
tabs: tabs.sh
@./tabs.sh
lastline: lastline.sh
@./lastline.sh
spaces: spaces.sh
@./spaces.sh

25
.github/checks/lastline.sh vendored Executable file
View File

@ -0,0 +1,25 @@
#! /bin/bash
OLDCWD=`pwd`
SCRIPT_PATH=`dirname $0`
CHECK_PATH=.
cd $SCRIPT_PATH/../../
nl='
'
nl=$'\n'
r1="${nl}$"
FILES=`find $CHECK_PATH -type f \( -name \*.inc -o -name Makefile -o -name \*.cfg -o -name \*.\[chs\] -o -name \*.mac -o -name \*.asm -o -name \*.sgml \) -print | while read f; do
t=$(tail -c2 $f; printf x)
[[ ${t%x} =~ $r1 ]] || echo "$f"
done`
cd $OLDCWD
if [ x"$FILES"x != xx ]; then
echo "error: found following files that have no newline at the end:" >&2
for n in $FILES; do
echo $n >&2
done
exit -1
fi

18
.github/checks/spaces.sh vendored Executable file
View File

@ -0,0 +1,18 @@
#! /bin/bash
OLDCWD=`pwd`
SCRIPT_PATH=`dirname $0`
CHECK_PATH=.
cd $SCRIPT_PATH/../../
FILES=`find $CHECK_PATH -type f \( -name \*.inc -o -name Makefile -o -name \*.cfg -o -name \*.\[chs\] -o -name \*.mac -o -name \*.asm -o -name \*.sgml \) -print | grep -v "libwrk/" | grep -v "testwrk/" | xargs grep -l ' $'`
cd $OLDCWD
if [ x"$FILES"x != xx ]; then
echo "error: found dangling spaces in the following files:" >&2
for n in $FILES; do
echo $n >&2
done
exit -1
fi

18
.github/checks/tabs.sh vendored Executable file
View File

@ -0,0 +1,18 @@
#! /bin/bash
OLDCWD=`pwd`
SCRIPT_PATH=`dirname $0`
CHECK_PATH=.
cd $SCRIPT_PATH/../../
FILES=`find $CHECK_PATH -type f \( \( -name \*.inc -a \! -name Makefile.inc \) -o -name \*.cfg -o -name \*.\[chs\] -o -name \*.mac -o -name \*.asm -o -name \*.sgml \) -print | grep -v "libwrk/" | grep -v "testwrk/" | xargs grep -l $'\t'`
cd $OLDCWD
if [ x"$FILES"x != xx ]; then
echo "error: found TABs in the following files:" >&2
for n in $FILES; do
echo $n >&2
done
exit -1
fi

View File

@ -21,6 +21,9 @@ jobs:
- name: Checkout Source
uses: actions/checkout@v2
- name: Do some simple style checks
shell: bash
run: make -j2 check
- name: Build the tools.
shell: bash
run: make -j2 bin USER_CFLAGS=-Werror

View File

@ -46,6 +46,9 @@ jobs:
- name: Checkout Source
uses: actions/checkout@v2
- name: Do some simple style checks
shell: bash
run: make -j2 check
- name: Build the tools.
shell: bash
run: |

3
.gitignore vendored
View File

@ -7,3 +7,6 @@
/testwrk/
/wrk/
/cc65.zip
/util/atari/*.exe
/util/gamate/*.exe

113
Contributing.md Normal file
View File

@ -0,0 +1,113 @@
This document contains all kinds of information that you should know if you want to contribute to the cc65 project. Before you start, please read all of it. If something is not clear to you, please ask - this document is an ongoing effort and may well be incomplete.
(''Note:'' The word "must" indicates a requirement. The word "should" indicates a recomendation.)
# generally
* You must obey these rules when contributing new code or documentation to cc65. We are well aware that not all existing code may respect all rules outlined here - but this is no reason for you not to respect them.
* One commit/patch/PR per issue. Do not mix several things unless they are very closely related.
# Codestyle rules
## All Sources
### TABs and spaces
This is an ongoing controversial topic - everyone knows that. However, the following is how we do it :)
* TAB characters must be expanded to spaces.
* 4 spaces per indention level (rather than 8) are preferred, especially if there are many different levels.
* No extra spaces at the end of lines.
* All text files must end with new-line characters. Don't leave the last line "dangling".
The (bash) scipts used to check the above rules can be found in ```.github/check```. You can also run all checks using ```make check```.
### misc
* 80 characters is the desired maximum width of files. But, it isn't a "strong" rule; sometimes, you will want to type longer lines, in order to keep the parts of expressions or comments together on the same line.
* You should avoid typing non-ASCII characters.
* If you change "normal" source code into comments, then you must add a comment about why that code is a comment.
* When you want to create a comment from several lines of code, you should use preprocessor lines, instead of ```/* */``` or "```;```". Example:
<pre>
#if 0
one ();
two ();
three = two () + one ();
#endif
</pre>
* You should type upper case characters for hex values.
* When you type zero-page addresses in hexadecimal, you should type two hex characters (after the hex prefix). When you type non-zero-page addresses in hex, you should type four hex characters.
* When you type lists of addresses, it is a good idea to sort them in ascending numerical order. That makes it easier for readers to build mental pictures of where things are in an address space. And, it is easier to see how big the variables and buffers are. Example:
<pre>
xCoord := $0703
yCoord := $0705 ; (this address implies that xCoord is 16 bits)
cmdbuf := $0706 ; (this address implies that yCoord is 8 bits)
cmdlen := $0786 ; (this address implies that cmdbuf is 128 bytes)
color := $0787
</pre>
## C Sources
* Your files should obey the C89 standard.
* All declarations in a block must be at the beginning of that block.
* You should put a blank line between a list of local variable declarations and the first line of code.
* You must use ANSI C comments (```/* */```); you must not use C++ comments (```//```).
* The normal indentation width should be four spaces.
* When a function's argument list wraps around to a next line, you should indent that next line by either the normal width or enough spaces to align it with the arguments on the previous line.
* When you add functions to an existing file, you should separate them by the same number of blank lines that separate the functions that already are in that file.
(The next two rules will be changed at some time in the future; but, for now:)
* You must separate function names and parameter/argument lists by one space.
* When declaring/defining pointers, you must put the asterisk (```*```) next to the data type, with a space between it and the variable's name. Examples:
<pre>
int* namedPtr[5];
char* nextLine (FILE* f);
</pre>
## Assembly Sources
* Op-code mnemonics must have lower-case letters. The names of instruction macroes may have upper-case letters.
* Hexadecimal number constants should be used except where decimal or binary numbers make much more sense in that constant's context.
* Hexadecimal letters should be upper-case.
* When you set two registers or two memory locations to an immediate 16-bit zero, you should use the expressions ```#<$0000``` and ```#>$0000``` (they make it obvious where you are putting the lower and upper bytes).
* If a function is declared to return a char-sized value, it actually must return an integer-sized value. (When cc65 promotes a returned value, it sometimes assumes that the value already is an integer.)
* Functions, that are intended for a platform's system library, should be optimized as much as possible.
* Sometimes, there must be a trade-off between size and speed. If you think that a library function won't be used often, then you should make it small. Otherwise, you should make it fast.
* Comments that are put on the right side of instructions must be aligned (start in the same character columns).
* Assembly source fields (label, operation, operand, comment) should start ''after'' character columns that are multiples of eight (such as 1, 9, 17, 33, and 41).
## LinuxDoc Sources
* TAB characters must be expanded to spaces.
* All text files must end with new-line characters. Don't leave the last line "dangling".
* 80 characters is the desired maximum width of files.
* You should avoid typing non-ASCII characters.
* You should put blank lines between LinuxDoc sections:
* Three blank lines between ```<sect>``` sections.
* Two blank lines between ```<sect1>``` sections.
* One blank line between other sections.
# Library implementation rules
* By default the toolchain must output a "standard" binary for the platform, no emulator formats, no extra headers used by tools. If the resulting binaries can not be run as is on emulators or eg flash cartridges, the process of converting them to something that can be used with these should be documented in the user manual.
* Generally every function should live in a seperate source file - unless the functions are so closely related that splitting makes no sense.
* Source files should not contain commented out code - if they do, there should be a comment that explains why that commented out code exists.
# Makefile rules
* Makefiles must generally work on both *nix (ba)sh and windows cmd.exe.
* Makefiles must not use external tools that are not provided by the cc65 toolchain itself.
The only exception to the above are actions that are exclusive to the github actions - those may rely on bash and/or linux tools.
# Documentation rules
## User manual (LinuxDoc)
* This is the primary documentation.
## Wiki
* The Wiki is strictly for additional information that does not fit into the regular user manual (LinuxDoc). The wiki must not duplicate any information that is present in the user manual

View File

@ -1,4 +1,4 @@
.PHONY: all mostlyclean clean install zip avail unavail bin lib doc html info samples test util
.PHONY: all mostlyclean clean install zip avail unavail bin lib doc html info samples test util check
.SUFFIXES:
@ -24,6 +24,9 @@ samples:
test:
@$(MAKE) -C test --no-print-directory $@
check:
@$(MAKE) -C .github/checks --no-print-directory $@
util:
@$(MAKE) -C util --no-print-directory $@

View File

@ -4,7 +4,9 @@
[Documentation](https://cc65.github.io/doc)
[Wiki](https://github.com/cc65/wiki/wiki)
[Contributing](Contributing.md) to the CC65 project.
The [Wiki](https://github.com/cc65/wiki/wiki) contains extra info that does not fit into the regular documentation.
[![Snapshot Build](https://github.com/cc65/cc65/actions/workflows/snapshot-on-push-master.yml/badge.svg?branch=master)](https://github.com/cc65/cc65/actions/workflows/snapshot-on-push-master.yml)
@ -27,6 +29,7 @@ including
- the Atari 8-bit machines.
- the Atari 2600 console.
- the Atari 5200 console.
- the Atari 7800 console.
- GEOS for the C64, C128 and Apple //e.
- the Bit Corporation Gamate console.
- the NEC PC-Engine (aka TurboGrafx-16) console.

8
asminc/atari7800.inc Normal file
View File

@ -0,0 +1,8 @@
; Atari 7800 TIA & RIOT read / write registers
;
; Karri Kaksonen (karri@sipo.fi), 2022
; TIA, RIOT & MARIA registers mapping
.include "atari7800_tia.inc"
.include "atari7800_riot.inc"
.include "atari7800_maria.inc"

View File

@ -0,0 +1,39 @@
; Atari 7800 MARIA read / write registers
;
; Read registers
BKGRND := $20
P0C1 := $21
P0C2 := $22
P0C3 := $23
MWSYNC := $24
P1C1 := $25
P1C2 := $26
P1C3 := $27
MSTAT := $28
P2C1 := $29
P2C2 := $2A
P2C3 := $2B
DPPH := $2C
P3C1 := $2D
P3C2 := $2E
P3C3 := $2F
DPPL := $30
P4C1 := $31
P4C2 := $32
P4C3 := $33
CHBASE := $34
P5C1 := $35
P5C2 := $36
P5C3 := $37
OFFSET := $38
P6C1 := $39
P6C2 := $3A
P6C3 := $3B
CTRL := $3C
P7C1 := $3D
P7C2 := $3E
P7C3 := $3F
; Write registers

20
asminc/atari7800_riot.inc Normal file
View File

@ -0,0 +1,20 @@
; Atari 7800 RIOT read / write registers
;
; Source: DASM - vcs.h
; Details available in: Stella Programmer's Guide by Steve Wright
;
; Florent Flament (contact@florentflament.com), 2017
; Read registers
SWCHA := $0280
CTLSWA := $0281
SWCHB := $0282
CTLSWB := $0283
INTIM := $0284
TIMINT := $0285
; Write registers
TIM1T := $0294
TIM8T := $0295
TIM64T := $0296
T1024T := $0297

69
asminc/atari7800_tia.inc Normal file
View File

@ -0,0 +1,69 @@
; Atari 7800 TIA read / write registers
;
; Source: DASM - vcs.h
; Details available in: Stella Programmer's Guide by Steve Wright
;
; Florent Flament (contact@florentflament.com), 2017
; Read registers
VSYNC := $00
VBLANK := $01
WSYNC := $02
RSYNC := $03
NUSIZ0 := $04
NUSIZ1 := $05
COLUP0 := $06
COLUP1 := $07
COLUPF := $08
COLUBK := $09
CTRLPF := $0A
REFP0 := $0B
REFP1 := $0C
PF0 := $0D
PF1 := $0E
PF2 := $0F
RESP0 := $10
RESP1 := $11
RESM0 := $12
RESM1 := $13
RESBL := $14
AUDC0 := $15
AUDC1 := $16
AUDF0 := $17
AUDF1 := $18
AUDV0 := $19
AUDV1 := $1A
GRP0 := $1B
GRP1 := $1C
ENAM0 := $1D
ENAM1 := $1E
ENABL := $1F
HMP0 := $20
HMP1 := $21
HMM0 := $22
HMM1 := $23
HMBL := $24
VDELP0 := $25
VDELP1 := $26
VDELBL := $27
RESMP0 := $28
RESMP1 := $29
HMOVE := $2A
HMCLR := $2B
CXCLR := $2C
; Write registers
CXM0P := $00
CXM1P := $01
CXP0FB := $02
CXP1FB := $03
CXM0FB := $04
CXM1FB := $05
CXBLPF := $06
CXPPMM := $07
INPT0 := $08
INPT1 := $09
INPT2 := $0A
INPT3 := $0B
INPT4 := $0C
INPT5 := $0D

View File

@ -275,7 +275,7 @@ XFWRITE = $3B ; Only in TELEMON 3.x write file (bank 7 of Orix
; Clock primitive
XRECLK = $3C ; Reset clock
XCLCL = $3D ; Close clock
XWRCLK = $3E ; Displays clock in the adress in A & Y registers
XWRCLK = $3E ; Displays clock in the address in A & Y registers
; Sound primitives
XSONPS = $40 ; Send data to PSG register (14 values)

67
cfg/atari7800.cfg Normal file
View File

@ -0,0 +1,67 @@
# Atari VCS 7800 linker configuration file for cc65
# In order to add the a78 header to the build you can add
# "--force-import __EXEHDR__" to the command line
SYMBOLS {
__STACKSIZE__: type = weak, value = $0600; # C stack
__CARTSIZE__: type = weak, value = $8000;
__VEC_BOTTOM__: value = $fffa, type = export;
__VEC_SIZE__: value = $6, type = export;
__ENCRYPT_BOTTOM__: value = $ff7a, type = export;
__ENCRYPT_SIZE__: value = $80, type = export;
__MEMORY_TOP__: value = __ENCRYPT_BOTTOM__, type = export;
__INIT_SIZE__: value = 121, type = export;
__MEMORY_INIT__: value = __MEMORY_TOP__ - __INIT_SIZE__, type = export;
__MEMORY_BOTTOM__: value = $10000 - __CARTSIZE__, type = weak;
__FREE_ROM_SIZE__: value = __MEMORY_INIT__ - __MEMORY_BOTTOM__, type = export;
}
MEMORY {
ZP: file = "", define = yes, start = $0040, size = $00C0, type = rw;
SP: file = "", define = yes, start = $0140, size = $00C0, type = rw;
RAM1: file = "", define = yes, start = $1800, size = $0840, type = rw;
RAM2: file = "", define = yes, start = $2100, size = $0040, type = rw;
RAM3: file = "", define = yes, start = $2200, size = $0600, type = rw;
# For emulators you also need a header file
HEADER: file = %O, start = $0000, size = 128;
# "Normal" cartridge rom. Multiple banks arent supported
# by this script. You may change the rom size, but keep
# two things in mind:
# - start must be a multiple of $1000
# - ROM must end at $ff79
ROM: file = %O, define = yes, start = __MEMORY_BOTTOM__, size = __FREE_ROM_SIZE__, type = ro, fill = yes, fillval = $ff;
ROMS: file = %O, define = yes, start = __MEMORY_INIT__, size = __INIT_SIZE__, type = ro, fill = yes, fillval = $ff;
# Encryption stuff
ROME: file = %O, start = __ENCRYPT_BOTTOM__, size = __ENCRYPT_SIZE__, type = ro, fill = yes, fillval = $ff;
# Interrupt vectors
ROMV: file = %O, start = __VEC_BOTTOM__, size = __VEC_SIZE__, type = ro, fill = yes, fillval = $ff;
}
SEGMENTS {
ZEROPAGE: load = ZP, type = zp;
EXEHDR: load = HEADER, type = ro, optional = yes;
STARTUP: load = ROMS, type = ro, define = yes;
ONCE: load = ROMS, type = ro, define = yes;
CODE: load = ROM, type = ro, define = yes;
RODATA: load = ROM, type = ro, define = yes, align = 256;
DATA: load = ROM, run = RAM1, type = rw, define = yes;
BSS: load = RAM1, type = bss, define = yes;
VECTORS: load = ROMV, type = ro, define = yes;
ENCRYPTION: load = ROME, type = ro define = yes;
}
FEATURES {
CONDES: type = constructor,
label = __CONSTRUCTOR_TABLE__,
count = __CONSTRUCTOR_COUNT__,
segment = ONCE;
CONDES: type = destructor,
label = __DESTRUCTOR_TABLE__,
count = __DESTRUCTOR_COUNT__,
segment = RODATA;
CONDES: type = interruptor,
label = __INTERRUPTOR_TABLE__,
count = __INTERRUPTOR_COUNT__,
segment = RODATA,
import = __CALLIRQ__;
}

View File

@ -29,7 +29,7 @@ MEMORY {
EXT: file = "", define = yes, start = $9000, size = $1000;
IO: file = "", define = yes, start = $A000, size = $1000;
RAE1: file = "", define = yes, start = $B000, size = $1000;
BASROM: file = "", define = yes, start = $C000, size = $1000;
BASROM: file = "", define = yes, start = $C000, size = $2000;
RAE2: file = "", define = yes, start = $E000, size = $1000;
TOP: file = "", define = yes, start = $F000, size = $1000;
}

View File

@ -29,7 +29,7 @@ MEMORY {
EXT: file = "", define = yes, start = $9000, size = $1000;
IO: file = "", define = yes, start = $A000, size = $1000;
RAE1: file = "", define = yes, start = $B000, size = $1000;
BASROM: file = "", define = yes, start = $C000, size = $1000;
BASROM: file = "", define = yes, start = $C000, size = $2000;
RAE2: file = "", define = yes, start = $E000, size = $1000;
TOP: file = "", define = yes, start = $F000, size = $1000;
}

View File

@ -29,7 +29,7 @@ MEMORY {
EXT: file = "", define = yes, start = $9000, size = $1000;
IO: file = "", define = yes, start = $A000, size = $1000;
RAE1: file = "", define = yes, start = $B000, size = $1000;
BASROM: file = "", define = yes, start = $C000, size = $1000;
BASROM: file = "", define = yes, start = $C000, size = $2000;
RAE2: file = "", define = yes, start = $E000, size = $1000;
TOP: file = "", define = yes, start = $F000, size = $1000;
}

View File

@ -370,7 +370,7 @@ The names in the parentheses denote the symbols to be used for static linking of
In memory constrained situations the memory from &dollar;803 to &dollar;1FFF
can be made available to a program by calling <tt/_heapadd ((void *) 0x0803, 0x17FD);/
at the beginning of <tt/main()/. Doing so is beneficial even if the program
doesn't use the the heap explicitly because loading the driver (and in fact
doesn't use the heap explicitly because loading the driver (and in fact
already opening the driver file) uses the heap implicitly.
</descrip><p>

View File

@ -376,7 +376,7 @@ The names in the parentheses denote the symbols to be used for static linking of
In memory constrained situations the memory from &dollar;803 to &dollar;1FFF
can be made available to a program by calling <tt/_heapadd ((void *) 0x0803, 0x17FD);/
at the beginning of <tt/main()/. Doing so is beneficial even if the program
doesn't use the the heap explicitly because loading the driver (and in fact
doesn't use the heap explicitly because loading the driver (and in fact
already opening the driver file) uses the heap implicitly.
</descrip><p>

157
doc/atari7800.sgml Normal file
View File

@ -0,0 +1,157 @@
<!doctype linuxdoc system>
<article>
<title>Atari 7800 specific information for cc65
<author>
<url url="mailto:karri@sipo.fi" name="Karri Kaksonen"><newline>
<abstract>
An overview over the Atari 7800 runtime system as it is implemented
for the cc65 C compiler.
</abstract>
<!-- Table of contents -->
<toc>
<!-- Begin the document -->
<sect>Overview<p>
This file contains an overview of the Atari 7800 runtime system as it
comes with the cc65 C compiler. It describes the memory layout, Atari
7800 specific header files and any pitfalls specific to that platform.
<sect>Binary format<p>
The default binary output format generated by the linker for the Atari
7800 target is a 48K cartridge image.
<sect>A78 header<p>
There is lots of different cart hardware available for the atari7800.
Some carts have ROM, RAM, sound hardware, non-volatile high score chips.
In order to know what kind of hardware the cart build requires there is
a header file of 128 bytes in front of the binary.
The default build creates a cart file for a 48K rom cart without any
extra features like the pokey audio chip or extra RAM.
In order to make cc65 more user friendly the build will add the a78
header automatically. This allows you to run the binary on emulators
and flash carts on the real console.
<sect>Encryption<p>
In order to boot the game in a mode that supports atari7800 functions
the cart must be encrypted after the linking phase.
There is a program called sign7800 that can be used to sign the cart.
The encryption is not required for running the cart on emulators.
You can also run atari2600 games without encryption.
<sect>Memory layout<p>
cc65 generated programs with the default setup can use RAM from
from &dollar;1800 to &dollar;203f.
The 4k RAM is then mapped to zero page area.
&dollar;2040 to &dollar;20ff is visible as zero page.
After that we have a vero small RAM area that is unused.
&dollar;2100 to &dollar;213f.
Then we mirror a second block from the RAM to become the hardware stack.
This would be from &dollar;2140 to &dollar;21ff.
The C-stack starts at &dollar;2800 and it can grow down to &dollar;2200.
size of the system stack can be customized by defining the
__STACKSIZE__ linker variable.
Special locations:
<descrip>
<tag/Stack/ The C runtime stack is located at &dollar;2800 -
__STACKSIZE__ and growing downwards.
<tag/Heap/ The C heap is located at &dollar;2200 and grows upwards.
</descrip><p>
<sect>Start-up condition<p>
When powered-up, the Atari 7800 TIA registers contain random
values. During the initialization phase, the start-up code needs to
initialize the TIA registers to sound values (or else the console has
an unpredictable behavior). In this implementation, zeros are written
to all of TIA registers during the start-up phase.
Note that RIOT registers (mostly timers) are left uninitialized, as
they don't have any consequence on the console behavior.
<sect>Platform specific header files<p>
Programs containing Atari 7800 specific code may use the
<tt/atari7800.h/ header file.
The following pseudo variables declared in the <tt/atari7800.h/ header
file allow access to the Atari 7800 TIA, MARIA & RIOT chips registers.
<descrip>
<tag><tt/TIA/</tag> The <tt/TIA/ structure allows read/write access
to the Atari 7800 TIA chip registers. See the <tt/_tia.h/ header
file located in the include directory for the declaration of the
structure. Also refer to the Stella Programmer's Guide by Steve
Wright for a detailed description of the chip and its registers.
<tag><tt/RIOT/</tag> The <tt/RIOT/ structure allows read/write
access to the Atari 7800 RIOT chip registers. See the
<tt/_riot.h/ header file located in the include directory for the
declaration of the structure. Also refer to the Stella Programmer's
Guide by Steve Wright for a detailed description of the chip and its
registers.
<tag><tt/MARIA/</tag> The <tt/MARIA/ structure allows read/write
access to the Atari 7800 MARIA chip registers. See the
<tt/_maria.h/ header file located in the include directory for the
declaration of the structure.
</descrip><p>
<sect>Loadable drivers<p>
There are no drivers for the Atari 7800.
<sect>Limitations<p>
TBD
<sect>Other hints<p>
One may write a custom linker configuration file to tune the memory
layout of a program. See the <tt/atari7800.cfg/ file in the cfg
directory as a starting point.
<sect>License<p>
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:
<enum>
<item> 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.
<item> Altered source versions must be plainly marked as such, and must not
be misrepresented as being the original software.
<item> This notice may not be removed or altered from any source
distribution.
</enum>
</article>

View File

@ -126,7 +126,7 @@ and &dollar;FF3F.
In memory constrained situations the memory from &dollar;400 to &dollar;7FF
can be made available to a program by calling <tt/_heapadd ((void *) 0x0400, 0x0400);/
at the beginning of <tt/main()/. Doing so is beneficial even if the program
doesn't use the the heap explicitly because loading a driver uses the heap implicitly.
doesn't use the heap explicitly because loading a driver uses the heap implicitly.
Using <tt/c64-soft80.o/ is as simple as placing it on the linker command
line like this:

View File

@ -3108,7 +3108,7 @@ See: <tt><ref id=".ASCIIZ" name=".ASCIIZ"></tt>,<tt><ref id=".CHARMAP" name=".CH
<sect1><tt>.IFDEF</tt><label id=".IFDEF"><p>
Conditional assembly: Check if a symbol is defined. Must be followed by
a symbol name. The condition is true if the the given symbol is already
a symbol name. The condition is true if the given symbol is already
defined, and false otherwise.
See also: <tt><ref id=".DEFINED" name=".DEFINED"></tt>
@ -3143,7 +3143,7 @@ See: <tt><ref id=".ASCIIZ" name=".ASCIIZ"></tt>,<tt><ref id=".CHARMAP" name=".CH
<sect1><tt>.IFNDEF</tt><label id=".IFNDEF"><p>
Conditional assembly: Check if a symbol is defined. Must be followed by
a symbol name. The condition is true if the the given symbol is not
a symbol name. The condition is true if the given symbol is not
defined, and false otherwise.
See also: <tt><ref id=".DEFINED" name=".DEFINED"></tt>
@ -3152,7 +3152,7 @@ See: <tt><ref id=".ASCIIZ" name=".ASCIIZ"></tt>,<tt><ref id=".CHARMAP" name=".CH
<sect1><tt>.IFNREF</tt><label id=".IFNREF"><p>
Conditional assembly: Check if a symbol is referenced. Must be followed
by a symbol name. The condition is true if if the the given symbol was
by a symbol name. The condition is true if the given symbol was
not referenced before, and false otherwise.
See also: <tt><ref id=".REFERENCED" name=".REFERENCED"></tt>
@ -3197,7 +3197,7 @@ See: <tt><ref id=".ASCIIZ" name=".ASCIIZ"></tt>,<tt><ref id=".CHARMAP" name=".CH
<sect1><tt>.IFREF</tt><label id=".IFREF"><p>
Conditional assembly: Check if a symbol is referenced. Must be followed
by a symbol name. The condition is true if if the the given symbol was
by a symbol name. The condition is true if the given symbol was
referenced before, and false otherwise.
This command may be used to build subroutine libraries in include files
@ -4763,6 +4763,7 @@ compiler, depending on the target system selected:
<item><tt/__APPLE2ENH__/ - Target system is <tt/apple2enh/
<item><tt/__ATARI2600__/ - Target system is <tt/atari2600/
<item><tt/__ATARI5200__/ - Target system is <tt/atari5200/
<item><tt/__ATARI7800__/ - Target system is <tt/atari7800/
<item><tt/__ATARI__/ - Target system is <tt/atari/ or <tt/atarixl/
<item><tt/__ATARIXL__/ - Target system is <tt/atarixl/
<item><tt/__ATMOS__/ - Target system is <tt/atmos/

View File

@ -198,6 +198,189 @@ Here is a description of all the command line options:
Enables debug mode, for debugging the behavior of cc65.
<tag><tt>--debug-tables name</tt></tag>
Writes symbol table information to a file, which includes details on structs, unions
functions, and global variables. For example, given the following code:
<tscreen><verb>
struct l {
unsigned char m;
unsigned char n;
};
struct hello {
unsigned char j;
unsigned char k;
struct l l;
};
struct sub {
unsigned char x;
unsigned char y;
};
union xy {
struct sub xy;
unsigned int mem;
};
typedef struct hello thingy;
unsigned char single;
unsigned char test_local_vars_main(void) {
static unsigned char wahoo;
static unsigned char bonanza = 0x42;
unsigned char i;
unsigned int j;
unsigned int *random;
unsigned char *lol;
signed char whoa;
struct hello wow;
thingy *cool;
union xy xy;
return 0;
}
</verb></tscreen>
The following output would be produced:
<tscreen><verb>
SC_FUNC: _test_local_vars_main: Symbol table
============================================
__fixargs__:
Flags: SC_CONST SC_DEF
Type: unsigned int
__argsize__:
Flags: SC_CONST SC_DEF
Type: unsigned char
wahoo:
AsmName: M0001
Flags: SC_STATIC SC_DEF SC_REF
Type: unsigned char
bonanza:
AsmName: M0002
Flags: SC_STATIC SC_DEF SC_REF
Type: unsigned char
i:
Flags: SC_AUTO SC_DEF SC_REF
Type: unsigned char
j:
Flags: SC_AUTO SC_DEF SC_REF
Type: unsigned int
random:
Flags: SC_AUTO SC_DEF SC_REF
Type: unsigned int *
lol:
Flags: SC_AUTO SC_DEF SC_REF
Type: unsigned char *
whoa:
Flags: SC_AUTO SC_DEF SC_REF
Type: signed char
wow:
Flags: SC_AUTO SC_DEF SC_REF
Type: struct hello
cool:
Flags: SC_AUTO SC_DEF SC_REF
Type: struct hello *
xy:
Flags: SC_AUTO SC_DEF SC_REF
Type: union xy
Global symbol table
===================
thingy:
AsmName: _thingy
Flags: SC_TYPEDEF 0x100000
Type: struct hello
single:
AsmName: _single
Flags: SC_STATIC SC_EXTERN SC_STORAGE SC_DEF SC_REF 0x100000
Type: unsigned char
test_local_vars_main:
AsmName: _test_local_vars_main
Flags: SC_FUNC SC_STATIC SC_EXTERN SC_DEF 0x100000
Type: unsigned char (void)
Global tag table
================
l:
Flags: SC_STRUCT SC_DEF
Type: (none)
hello:
Flags: SC_STRUCT SC_DEF
Type: (none)
sub:
Flags: SC_STRUCT SC_DEF
Type: (none)
xy:
Flags: SC_UNION SC_DEF
Type: (none)
Global struct and union definitions
=========================
SC_STRUCT: l
============
m:
Flags: SC_STRUCTFIELD
Type: unsigned char
n:
Flags: SC_STRUCTFIELD
Type: unsigned char
SC_STRUCT: hello
================
j:
Flags: SC_STRUCTFIELD
Type: unsigned char
k:
Flags: SC_STRUCTFIELD
Type: unsigned char
l:
Flags: SC_STRUCTFIELD
Type: struct l
SC_STRUCT: sub
==============
x:
Flags: SC_STRUCTFIELD
Type: unsigned char
y:
Flags: SC_STRUCTFIELD
Type: unsigned char
SC_UNION: xy
============
xy:
Flags: SC_STRUCTFIELD
Type: struct sub
mem:
Flags: SC_STRUCTFIELD
Type: unsigned int
</verb></tscreen>
<tag><tt>--debug-opt name</tt></tag>
The named file contains a list of specific optimization steps to enable or disable.

View File

@ -6127,7 +6127,7 @@ pointer you're passing somewhere else, otherwise
<tscreen><verb>
ptr = realloc (ptr, size);
</verb></tscreen>
will loose your only copy of <tt/ptr/ if <tt/realloc/ returns <tt/NULL/.
will lose your only copy of <tt/ptr/ if <tt/realloc/ returns <tt/NULL/.
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>

View File

@ -124,6 +124,9 @@
<tag><htmlurl url="atari5200.html" name="atari5200.html"></tag>
Topics specific to the Atari 5200 Game Console.
<tag><htmlurl url="atari7800.html" name="atari7800.html"></tag>
Topics specific to the Atari 7800 Game Console.
<tag><htmlurl url="atmos.html" name="atmos.html"></tag>
Topics specific to the Oric Atmos.

View File

@ -500,7 +500,7 @@ prompt.
Before you can run the cartridge image produced by the linker, the binary has to
be patched using the <bf/gamate-fixcart/ tool that is included in the cc65
package in the util/gamata directory.
package in the util/gamate/ directory.
<tscreen><verb>
gamate-fixcart <image.bin>

View File

@ -166,6 +166,7 @@ Here is a description of all of the command-line options:
<item>apple2
<item>apple2enh
<item>atari2600
<item>atari7800
<item>atari
<item>atarixl
<item>atmos

View File

@ -15,21 +15,40 @@ An overview over the Sym-1 runtime system as it is implemented for the cc65 C co
<sect>Overview<p>
This file contains an overview of the Sym-1 runtime system as it comes with the cc65 C compiler. It describes the memory layout, Sym-1 specific header files, available drivers, and any pitfalls specific to the platform.
This file contains an overview of the Sym-1 runtime system as it comes with the cc65 C compiler.
It describes the memory layout, Sym-1 specific header files, available drivers, and any pitfalls
specific to the platform.
Please note that Sym-1 specific functions are just mentioned here, they are described in detail in the separate <url url="funcref.html" name="function reference">. Even functions marked as "platform dependent" may be available on more than one platform. Please see the function reference for more information.
Please note that Sym-1 specific functions are just mentioned here, they are described in detail
in the separate <url url="funcref.html" name="function reference">. Even functions marked as
&quot;platform dependent&quot; may be available on more than one platform. Please see the
function reference for more information.
<sect>Binary format<p>
The output format generated by the linker for the Sym-1 target is a raw binary BIN file, which is essentially a memory image. You can convert this to a HEX file using BIN2HEX, which is a popular open-source conversion utility program. A HEX file has ASCII representations of the hexadecimal byte values of the machine-language program. So the HEX file can be transferred to the Sym-1 using the RS-232 terminal port, just as if the machine-code was entered by hand. Enter 'm 200' in the monitor and start the HEX file transfer.
The output format generated by the linker for the Sym-1 target is a raw binary BIN file, which
is essentially a memory image. You can convert this to a HEX file using BIN2HEX, which is a
popular open-source conversion utility program. A HEX file has ASCII representations of the
hexadecimal byte values of the machine-language program. So the HEX file can be transferred
to the Sym-1 using the RS-232 terminal port, just as if the machine-code was entered by hand.
Enter 'm 200' in the monitor and start the HEX file transfer.
<p>
Included with this distribution is a 4k configuration file and a 32k config file. The Sym-1 on-board memory is limited to 4 kbytes but system memory can be increased to 32 kbytes of contiguous RAM with aftermarket add-on boards. So choose the config file that matches your system configuration before compiling and linking user programs.
Included with this distribution is a 4k configuration file and a 32k config file. The Sym-1
on-board memory is limited to 4 kbytes but system memory can be increased to 32 kbytes of
contiguous RAM with aftermarket add-on boards. So choose the config file that matches your
system configuration before compiling and linking user programs.
<sect>Memory layout<p>
The ROMs and I/O areas are defined in the configuration files, as are most of the entry points for useful subroutines in the Sym-1 monitor ROM. cc65 generated programs compiled and linked using 4k config run in the memory range of &dollar;200 - &dollar;0FFF. The 32k config expands this range to &dollar;7FFF. The starting memory location and entry point for running the program is &dollar;200, so when the program is transferred to the Sym-1, it is executed by typing 'g 200'. The system returns control back to the monitor ROM when the program terminates, providing the '.' prompt.
The ROMs and I/O areas are defined in the configuration files, as are most of the entry points
for useful subroutines in the Sym-1 monitor ROM. cc65 generated programs compiled and linked
using 4k config run in the memory range of &dollar;200 - &dollar;0FFF. The 32k config expands
this range to &dollar;7FFF. Memory above 32k can be used to extend the heap, as described below.
The starting memory location and entry point for running the program is &dollar;200, so when the
program is transferred to the Sym-1, it is executed by typing 'g 200'. The system returns control
back to the monitor ROM when the program terminates, providing the '.' prompt.
Special locations:
@ -38,10 +57,12 @@ Special locations:
Conio support is not currently available for the Sym-1. But stdio console functions are available.
<tag/Stack/
The C runtime stack is located at &dollar;0FFF on 4KB Syms, or at &dollar;7FFF for 32KB systems. The stack always grows downwards.
The C runtime stack is located at &dollar;0FFF on 4kb Syms, or at &dollar;7FFF for 32kb systems.
The stack always grows downwards.
<tag/Heap/
The C heap is located at the end of the program and grows towards the C runtime stack.
The C heap is located at the end of the program and grows towards the C runtime stack. Extended
memory can be added to the heap, as described below.
</descrip><p>
@ -51,7 +72,8 @@ Programs containing Sym-1 code may use the <tt/sym1.h/ header file. See the hea
<sect1>Hardware access<p>
The pseudo variables declared in the <tt/sym1.inc/ include file allow access to hardware located in the address space. See the include file for more information.
The pseudo variables declared in the <tt/sym1.inc/ include file allow access to hardware located in the
address space. See the include file for more information.
<sect>Loadable drivers<p>
@ -61,7 +83,9 @@ No graphics drivers are currently available for the Sym-1.
<sect1>Extended memory drivers<p>
No extended memory drivers are currently available for the Sym-1.
There are no extended memory drivers for the Sym-1. However, there is a way to access memory beyond the
32kb boundary, if extended memory is physically present in the system. See the example program,
symExtendedMemory, in the samples directory.
<sect1>Joystick drivers<p>
@ -73,7 +97,8 @@ No mouse drivers are currently available for the Sym-1.
<sect1>RS232 device drivers<p>
No communication port drivers are currently available for the Sym-1. It has only the &quot;master console&quot; e.g. stdin and stdout.
No communication port drivers are currently available for the Sym-1. It has only the &quot;master console&quot;
e.g. stdin and stdout.
<sect>Limitations<p>
@ -94,29 +119,45 @@ To be more specific, this limitation means that you cannot use any of the follow
<sect>Other hints<p>
<sect1>sym1.h<p>
This header exposes Sym-specific I/O functions that are useful for reading and writing its ports and front panel. See the <tt/sym1.h/ include file for a list of the functions available.
This header exposes Sym-specific I/O functions that are useful for reading and writing its ports and front panel.
See the <tt/sym1.h/ include file for a list of the functions available.
<sect2>Limited memory applications<p>
As stated earlier, there are config files for 4KB and 32KB systems. If you have 32KB RAM, then you will probably want to use the sym1-32k configuration, but if not - if you are using the sym1-4k configuration - then you may want to use functions like getchar, putchar, gets and puts rather than functions like scanf and printf. Printf, for example, requires about 1KB because it needs to know how to process all the format specifiers.
As stated earlier, there are config files for 4kb and 32kb systems. If you have 32kb RAM, then you will probably
want to use the sym1-32k configuration, but if not - if you are using the sym1-4k configuration - then you may
want to use functions like getchar, putchar, gets and puts rather than functions like scanf and printf.
Printf, for example, requires about 1KB because it needs to know how to process all the format specifiers.
<sect3>Sample programs<p>
<sect3>Using extended memory<p>
All the samples will run on the &quot;stock&quot; 4KB Sym-1, except for symIO and symNotepad, which require 32KB. These sample programs can be found in the samples/sym1 directory:
Memory may be physically present that is addressed at locations above the monitor ROM at $8000. This extended
memory is accessible by adding to the heap, as described in the symExtendedMemory sample program.
<sect4>Sample programs<p>
All the samples will run on the &quot;stock&quot; 4kb Sym-1, except for symIO and symNotepad, which require 32kb.
Additionally, symExtendedMemory shows how to access memory above 32kb, so it expects more than 32kb.
These sample programs can be found in the samples/sym1 directory:
<itemize>
<item>symHello prints &quot;Hello World!&quot; and then inputs characters, which are echoed on the screen. It also makes a &quot;beep&quot; sound.</item>
<item>symTiny does the same as symHello, but does it with puts() rather than printf() to show the difference in compiled binary size.</item>
<item>symHello prints &quot;Hello World!&quot; and then inputs characters, which are echoed on the screen.
It also makes a &quot;beep&quot; sound.</item>
<item>symTiny does the same as symHello, but does it with puts() rather than printf() to show the difference
in compiled binary size.</item>
<item>symDisplay allows entry of a message, which is then displayed by scrolling it across the front panel display.</item>
<item>symIO allows access to the Sym-1 digital I/O ports.</item>
<item>symNotepad is a simple text entry/retrieval program that uses tape storage.</item>
<item>symExtendedMemory demonstrates how to access upper-memory and add it to the heap.</item>
</itemize>
<sect>License<p>
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.
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:
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:
<enum>
<item> The origin of this software must not be misrepresented; you must not

View File

@ -76,13 +76,13 @@ ifneq ($(MAKECMDGOALS),clean)
endif
%.o: %.c
$(CC) -c $(CFLAGS) -o $@ $<
&#9;$(CC) -c $(CFLAGS) -o $@ $<
$(PROGRAM): $(SOURCES:.c=.o)
$(CC) $(LDFLAGS) -o $@ $^
&#9;$(CC) $(LDFLAGS) -o $@ $^
clean:
$(RM) $(SOURCES:.c=.o) $(SOURCES:.c=.d) $(PROGRAM) $(PROGRAM).map
&#9;$(RM) $(SOURCES:.c=.o) $(SOURCES:.c=.d) $(PROGRAM) $(PROGRAM).map
</verb></tscreen>
<bf/Important:/ When using the sample Makefile above via copy & paste it is

View File

@ -105,7 +105,7 @@ struct __dos2x {
unsigned char* zbufp; /* points to user filename */
unsigned char* zdrva; /* points to serveral buffers (mostly VTOC) */
unsigned char* zsba; /* points to sector buffer */
unsigned char errno; /* number of occured error */
unsigned char errno; /* number of occurred error */
};
typedef struct __dos2x dos2x_t;

63
include/_maria.h Normal file
View File

@ -0,0 +1,63 @@
/*****************************************************************************/
/* */
/* _maria.h */
/* */
/* Atari 7800, Maria chip register hardware structures */
/* */
/* */
/* 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. */
/* */
/*****************************************************************************/
/*
* MARIA registers
*/
struct __maria {
unsigned char bkgrnd;
unsigned char p0c1;
unsigned char p0c2;
unsigned char p0c3;
unsigned char wsync;
unsigned char p1c1;
unsigned char p1c2;
unsigned char p1c3;
unsigned char mstat;
unsigned char p2c1;
unsigned char p2c2;
unsigned char p2c3;
unsigned char dpph;
unsigned char p3c1;
unsigned char p3c2;
unsigned char p3c3;
unsigned char dppl;
unsigned char p4c1;
unsigned char p4c2;
unsigned char p4c3;
unsigned char chbase;
unsigned char p5c1;
unsigned char p5c2;
unsigned char p5c3;
unsigned char offset;
unsigned char p6c1;
unsigned char p6c2;
unsigned char p6c3;
unsigned char ctrl;
unsigned char p7c1;
unsigned char p7c2;
unsigned char p7c3;
};

65
include/atari7800.h Normal file
View File

@ -0,0 +1,65 @@
/*****************************************************************************/
/* */
/* Atari VCS 7800 TIA & RIOT registers addresses */
/* */
/* Karri Kaksonen (karri@sipo.fi), 2022 */
/* */
/* */
/*****************************************************************************/
#ifndef _ATARI7800_H
#define _ATARI7800_H
/* Check for errors */
#if !defined(__ATARI7800__)
# error This module may only be used when compiling for the Atari 7800!
#endif
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/* Color defines */
#define COLOR_BLACK 0x00
#define COLOR_GREY 0x01
#define COLOR_LIGHTGREY 0x02
#define COLOR_WHITE 0x03
/* TGI color defines (default palette) */
#define TGI_COLOR_BLACK COLOR_BLACK
#define TGI_COLOR_GREY COLOR_GREY
#define TGI_COLOR_LIGHTGREY COLOR_LIGHTGREY
#define TGI_COLOR_WHITE COLOR_WHITE
/* Masks for joy_read */
#define JOY_RIGHT_MASK 0x80
#define JOY_LEFT_MASK 0x40
#define JOY_DOWN_MASK 0x20
#define JOY_UP_MASK 0x10
#define JOY_BTN_1_MASK 0x01
#define JOY_BTN_2_MASK 0x02
#define JOY_BTN_A_MASK JOY_BTN_1_MASK
#define JOY_BTN_B_MASK JOY_BTN_2_MASK
#define JOY_BTN_A(v) ((v) & JOY_BTN_A_MASK)
#define JOY_BTN_B(v) ((v) & JOY_BTN_B_MASK)
/* No support for dynamically loadable drivers */
#define DYN_DRV 0
#include <_tia.h>
#define TIA (*(struct __tia*)0x0000)
#include <_riot.h>
#define RIOT (*(struct __riot*)0x0280)
#include <_maria.h>
#define MARIA (*(struct __maria*)0x0020)
/* End of atari7800.h */
#endif

View File

@ -59,21 +59,21 @@ unsigned long __fastcall__ udiv32by16r16 (unsigned long rhs, unsigned lhs);
*/
int __fastcall__ imul8x8r16 (signed char lhs, signed char rhs);
/* Multiplicate two signed 8 bit to yield an signed 16 bit result */
/* Multiply two signed 8 bit to yield an signed 16 bit result */
long __fastcall__ imul16x16r32 (int lhs, int rhs);
/* Multiplicate two signed 16 bit to yield a signed 32 bit result */
/* Multiply two signed 16 bit to yield a signed 32 bit result */
unsigned __fastcall__ umul8x8r16 (unsigned char lhs, unsigned char rhs);
/* Multiplicate two unsigned 8 bit to yield an unsigned 16 bit result */
/* Multiply two unsigned 8 bit to yield an unsigned 16 bit result */
unsigned long __fastcall__ umul16x8r32 (unsigned lhs, unsigned char rhs);
/* Multiplicate an unsigned 16 bit by an unsigned 8 bit number yielding a 24
/* Multiply an unsigned 16 bit by an unsigned 8 bit number yielding a 24
** bit unsigned result that is extended to 32 bits for easier handling from C.
*/
unsigned long __fastcall__ umul16x16r32 (unsigned lhs, unsigned rhs);
/* Multiplicate two unsigned 16 bit to yield an unsigned 32 bit result */
/* Multiply two unsigned 16 bit to yield an unsigned 32 bit result */
unsigned int __fastcall__ mul20 (unsigned char value);
/* Multiply an 8 bit unsigned value by 20 and return the 16 bit unsigned

View File

@ -145,6 +145,8 @@
/* constants for the conio implementation */
#define COLOR_BLACK 0x03
#define COLOR_GRAY2 0x02
#define COLOR_GRAY1 0x01
#define COLOR_WHITE 0x00
#define CH_HLINE 1

View File

@ -52,24 +52,25 @@
/* Color defines */
#define COLOR_BLACK 0x00
#define COLOR_RED 0x01
#define COLOR_PINK 0x02
#define COLOR_LIGHTGREY 0x03
#define COLOR_GREY 0x04
#define COLOR_DARKGREY 0x05
#define COLOR_BROWN 0x06
#define COLOR_PEACH 0x07
#define COLOR_YELLOW 0x08
#define COLOR_LIGHTGREEN 0x09
#define COLOR_GREEN 0x0A
#define COLOR_DARKBROWN 0x0B
#define COLOR_TRANSPARENT 0x00
#define COLOR_BLACK 0x01
#define COLOR_RED 0x02
#define COLOR_PINK 0x03
#define COLOR_LIGHTGREY 0x04
#define COLOR_GREY 0x05
#define COLOR_DARKGREY 0x06
#define COLOR_BROWN 0x07
#define COLOR_PEACH 0x08
#define COLOR_YELLOW 0x09
#define COLOR_LIGHTGREEN 0x0A
#define COLOR_GREEN 0x0B
#define COLOR_VIOLET 0x0C
#define COLOR_BLUE 0x0D
#define COLOR_LIGHTBLUE 0x0E
#define COLOR_WHITE 0x0F
/* TGI color defines (default palette) */
#define TGI_COLOR_TRANSPARENT COLOR_TRANSPARENT
#define TGI_COLOR_BLACK COLOR_BLACK
#define TGI_COLOR_RED COLOR_RED
#define TGI_COLOR_PINK COLOR_PINK
@ -81,7 +82,6 @@
#define TGI_COLOR_YELLOW COLOR_YELLOW
#define TGI_COLOR_LIGHTGREEN COLOR_LIGHTGREEN
#define TGI_COLOR_GREEN COLOR_GREEN
#define TGI_COLOR_DARKBROWN COLOR_DARKBROWN
#define TGI_COLOR_VIOLET COLOR_VIOLET
#define TGI_COLOR_BLUE COLOR_BLUE
#define TGI_COLOR_LIGHTBLUE COLOR_LIGHTBLUE

View File

@ -43,6 +43,8 @@
# include <atari2600.h>
#elif defined(__ATARI5200__)
# include <atari5200.h>
#elif defined(__ATARI7800__)
# include <atari7800.h>
#elif defined(__ATMOS__)
# include <atmos.h>
#elif defined(__CBM__)

View File

@ -21,6 +21,7 @@ TARGETS = apple2 \
atarixl \
atari2600 \
atari5200 \
atari7800 \
atmos \
creativision \
$(CBMS) \

View File

@ -129,7 +129,7 @@ setbuf: lda #$00 ; Low byte
.assert MLI::OPEN::PATHNAME = MLI::INFO::PATHNAME, error
; Lower file level to avoid program file
; being closed by C libary shutdown code
; being closed by C library shutdown code
ldx LEVEL
stx level
beq :+
@ -185,13 +185,13 @@ setbuf: lda #$00 ; Low byte
lda #$00 ; '\0'
beq :- ; Branch always
; Call loader stub after C libary shutdown
; Call loader stub after C library shutdown
: lda #<target
ldx #>target
sta done+1
stx done+2
; Initiate C libary shutdown
; Initiate C library shutdown
jmp _exit
.bss

69
libsrc/atari7800/clock.s Normal file
View File

@ -0,0 +1,69 @@
;
; 2022-03-15, Karri Kaksonen
;
; clock_t clock (void);
;
.export _clock, clock_count
.interruptor update_clock, 2 ; (low priority)
.constructor init_clock
.import sreg: zp
.import _zonecounter
.include "atari7800.inc"
.macpack generic
.code
;-----------------------------------------------------------------------------
; Read the clock counter.
;
.proc _clock
lda #0
sta sreg+1 ; Promote 24 bits up to 32 bits
lda clock_count+2
sta sreg
ldx clock_count+1
lda clock_count
rts
.endproc
;-----------------------------------------------------------------------------
; This interrupt handler increments a 24-bit counter at every video
; vertical-blanking time.
; Update the clock only on interrupt while the drawing on screen is on
; _zonecounter == 1 (from 1st visible scanline to last visible scanline)
;
update_clock:
lda _zonecounter
and #01
beq @L1
inc clock_count
bne @L1
inc clock_count+1
bne @L1
inc clock_count+2
@L1: ;clc ; General interrupt was not reset
rts
;-----------------------------------------------------------------------------
; Set time to zero at startup
;
.segment "ONCE"
init_clock:
lda #0
sta clock_count+2
sta clock_count+1
sta clock_count
rts
;-----------------------------------------------------------------------------
; Store time in 3 bytes
;
.bss
clock_count:
.res 3

View File

@ -0,0 +1,34 @@
;
; 2022-03-15, Karri Kaksonen
;
; clock_t _clocks_per_sec (void);
;
.export __clocks_per_sec
.import sreg: zp
.import _paldetected
.include "atari7800.inc"
.macpack generic
.code
;-----------------------------------------------------------------------------
; Return the number of clock ticks in one second.
;
.proc __clocks_per_sec
lda #0
tax
sta sreg ; return 32 bits
sta sreg+1
lda _paldetected
bne pal
lda #60 ; NTSC - 60Hz
rts
pal:
lda #50 ; PAL - 50Hz
rts
.endproc

71
libsrc/atari7800/crt0.s Normal file
View File

@ -0,0 +1,71 @@
.export _zonecounter
.export __STARTUP__ : absolute = 1
.export _exit
.import __ROM_START__
.import __RAM3_START__, __RAM3_SIZE__
.import initlib, donelib
.import zerobss, copydata
.import IRQStub
.import push0, _main
.include "atari7800.inc"
.include "zeropage.inc"
INPTCTRL = $01
.segment "STARTUP"
start:
; Startup sequence recommended by Atari.
; See the 7800 standards document.
sei ; Initialize 6502
cld
lda #$07 ; Lock machine in 7800 mode
sta INPTCTRL
lda #$7f ; DMA off
sta CTRL
ldx #0 ; OFFSET must always be 0
stx OFFSET
stx INPTCTRL ; Make sure joysticks don't freeze
dex ; Stack pointer = $ff
txs
; Set up parameter stack
lda #<(__RAM3_START__ + __RAM3_SIZE__)
sta sp
lda #>(__RAM3_START__ + __RAM3_SIZE__)
sta sp+1
jsr copydata
jsr zerobss
jsr initlib
; Call main program (pass empty command line)
jsr push0 ; argc
jsr push0 ; argv
ldy #4 ; Argument size
jsr _main
_exit:
jsr donelib
jmp start
NMIHandler:
inc _zonecounter
jmp IRQStub
IRQHandler:
rti
.segment "DATA"
_zonecounter:
.byte 0
.segment "ENCRYPTION"
.res 126, $ff ; Reserved for encryption
Lfff8: .byte $ff ; Region verification (always $ff)
Lfff9: .byte $f7 ; Use last 4096 bytes only for encryption
;;;Lfff9: .byte <(((__ROM_START__/4096)<<4) | 7)
.segment "VECTORS"
.word NMIHandler
.word start
.word IRQHandler

5
libsrc/atari7800/ctype.s Normal file
View File

@ -0,0 +1,5 @@
; Character specification table.
;
; uses the "common" definition
.include "ctype_common.inc"

46
libsrc/atari7800/exehdr.s Normal file
View File

@ -0,0 +1,46 @@
;
; Karri Kaksonen, 2022
;
; This header contains data for emulators
;
.export __EXEHDR__: absolute = 1
.import __CARTSIZE__
; ------------------------------------------------------------------------
; EXE header
.segment "EXEHDR"
.byte 3 ; version
.byte 'A','T','A','R','I','7','8','0','0',' ',' ',' ',' ',' ',' ',' '
.byte 'G','a','m','e',' ','n','a','m','e',0,0,0,0,0,0,0
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.byte 0,0,>__CARTSIZE__,0 ; Set the cart size in the cfg file
; bit 0 - pokey at 4000
; bit 1 - supergame bank switched
; bit 2 - supergame ram at $4000
; bit 3 - rom at $4000
; bit 4 - bank 6 at $4000
; bit 5 - supergame banked ram
; bit 6 - pokey at $450
; bit 7 - mirror ram at $4000
; bit 8 - activision banking
; bit 9 - absolute banking
; bit 10 - pokey at $440
; bit 11 - ym2151 at $461/462
; bit 12 - souper
; bit 13-15 - Special
; 0 = Normal cart
.byte 0,0 ; 0 = Normal cart
.byte 1 ; 1 = Joystick, 2 = lightgun
.byte 0 ; No joystick 2
.byte 0 ; bit0 = 0:NTSC,1:PAL bit1 = 0:component,1:composite
.byte 0 ; Save data peripheral - 1 byte (version 2)
; 0 = None / unknown (default)
; 1 = High Score Cart (HSC)
; 2 = SaveKey
.byte 0 ; 63 Expansion module
; 0 = No expansion module (default on all currently released games)
; 1 = Expansion module required
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.byte 0,0,0,0,0,0,0,0
.byte 'A','C','T','U','A','L',' ','C','A','R','T',' ','D','A','T','A',' ','S','T','A','R','T','S',' ','H','E','R','E'

65
libsrc/atari7800/get_tv.s Normal file
View File

@ -0,0 +1,65 @@
;
; Karri Kaksonen, 2022-03-25
;
; unsigned char get_tv (void)
;
.include "atari7800.inc"
.include "get_tv.inc"
.export _get_tv
.export _paldetected
.segment "DATA"
_paldetected:
.byte $FF
; ---------------------------------------------------------------
; unsigned char get_tv (void)
; ---------------------------------------------------------------
.segment "CODE"
.proc _get_tv: near
.segment "CODE"
ldx #$00
lda #$FF
cmp _paldetected
bne L8
L1: lda MSTAT
and #$80
bne L1
L2: lda MSTAT
and #$80
beq L2
L3: lda MSTAT
and #$80
bne L3
lda #$00
sta M0001
jmp L5
L4: sta MWSYNC
sta MWSYNC
dec M0001
L5: lda MSTAT
and #$80
beq L4
lda M0001
cmp #$78
bcc L6
lda #TV::NTSC
jmp L7
L6: lda #TV::PAL
L7: sta _paldetected
ldx #$00
L8: lda _paldetected
rts
.segment "BSS"
M0001:
.res 1,$00
.endproc

36
libsrc/atari7800/irq.s Normal file
View File

@ -0,0 +1,36 @@
;
; IRQ handling (Atari 7800 version)
;
.export initirq, doneirq, IRQStub
.import __INTERRUPTOR_COUNT__, callirq
.include "atari7800.inc"
.code
; ------------------------------------------------------------------------
initirq:
doneirq:
rts
; ------------------------------------------------------------------------
IRQStub:
cld ; Just to be sure
pha
lda #<(__INTERRUPTOR_COUNT__ * 2)
beq @L1
txa
pha
tya
pha
jsr callirq ; Call the functions
pla
tay
pla
tax
@L1: pla
rti

View File

@ -0,0 +1,161 @@
;
; Standard joystick driver for the Atari 7800.
; This version tries to use 7800 and 2600 joysticks.
; But assumes that both joysticks are of same type.
;
; Modified by Karri Kaksonen, 2022-03-31
; Ullrich von Bassewitz, 2002-12-20
; Using code from Steve Schmidtke
;
.include "zeropage.inc"
.include "joy-kernel.inc"
.include "joy-error.inc"
.include "atari7800.inc"
.macpack generic
.macpack module
; ------------------------------------------------------------------------
; Header. Includes jump table
module_header _atari7800_stdjoy_joy
; Driver signature
.byte $6A, $6F, $79 ; "joy"
.byte JOY_API_VERSION ; Driver API version number
; Library reference
.addr $0000
; Jump table.
.addr INSTALL
.addr UNINSTALL
.addr COUNT
.addr READ
; ------------------------------------------------------------------------
; Constants
JOY_COUNT = 2 ; Number of joysticks we support
.code
; ------------------------------------------------------------------------
; INSTALL routine. Is called after the driver is loaded into memory. If
; possible, check if the hardware is present and determine the amount of
; memory available.
; Must return an JOY_ERR_xx code in a/x.
;
INSTALL:
; Assume 7800 2-button controller, can change
; to 2600 1-button later
lda #$14
sta CTLSWB ; enable 2-button 7800 controller 1: set pin 6 to output
ldy #$00
sty SWCHB ; enable 2-button 7800 controller 2: pull pin 6 (INPT4) high
reset:
lda #<JOY_ERR_OK
ldx #>JOY_ERR_OK
; rts ; Run into UNINSTALL instead
; ------------------------------------------------------------------------
; UNINSTALL routine. Is called before the driver is removed from memory.
; Can do cleanup or whatever. Must not return anything.
;
UNINSTALL:
rts
; ------------------------------------------------------------------------
; COUNT: Return the total number of available joysticks in a/x.
;
COUNT:
lda #<JOY_COUNT
ldx #>JOY_COUNT
rts
; ------------------------------------------------------------------------
; READ: Read a particular joystick passed in A for 2 fire buttons.
readbuttons:
; Y has joystick of interest 0/1
; return value:
; $00: no button,
; $01: left/B button,
; $02: right/A button,
; $03: both buttons
; preserves X
tya
beq L5
; Joystick 1 processing
; 7800 joystick 1 buttons
ldy #0 ; ........
bit INPT2 ; Check for right button
bpl L1
ldy #2 ; ......2.
L1: bit INPT3 ;Check for left button
bpl L2
iny ; ......21
L2: tya
bne L4 ; 7800 mode joystick worked
; 2600 Joystick 1
bit INPT5
bmi L4
L3: iny ; .......1
lda #0 ; Fallback to 2600 joystick mode
sta CTLSWB
L4: tya ; ......21
rts
L5: ; Joystick 0 processing
; 7800 joystick 0 buttons
ldy #0 ; ........
bit INPT0 ; Check for right button
bpl L6
ldy #2 ; ......2.
L6: bit INPT1 ;Check for left button
bpl L7
iny ; ......21
L7: tya
bne L4 ; 7800 mode joystick worked
; 2600 Joystick 0
bit INPT4
bmi L4
bpl L3
READ:
tay ; Store joystick 0/1 in Y
beq L8
lda SWCHA ; Read directions of joystick 1
rol ; ...RLDU.
rol ; ..RLDU..
rol ; .RLDU... - joystick 1
jmp L9
L8: lda SWCHA ; Read directions of joystick 0
ror ; .RLDU... - joystick 0
L9: tax
jsr readbuttons ; A = ......21, X = .RLDU...
ror ; A = .......2 1
tay ; Y = .......2
txa ; A = .RLDU...
ror ; A = 1.RLDU..
tax ; X = 1.RLDU..
tya ; A = .......2
ror ; A = ........ 2
txa ; A = 1.RLDU..
rol ; A = .RLDU..2 1
rol ; A = RLDU..21
eor #$F0 ; The direction buttons were inversed
and #$F3
rts

View File

@ -0,0 +1,14 @@
;
; Address of the static standard joystick driver
;
; Oliver Schmidt, 2012-11-01
;
; const void joy_static_stddrv[];
;
.export _joy_static_stddrv
.import _atari7800_stdjoy_joy
.rodata
_joy_static_stddrv := _atari7800_stdjoy_joy

View File

@ -0,0 +1,8 @@
;
; Oliver Schmidt, 2013-05-31
;
.export joy_libref
.import _exit
joy_libref := _exit

View File

@ -72,7 +72,7 @@ reu_params: .word $0000 ; Host address, lo, hi
.byte $00 ; Expansion bank no.
.word $0000 ; # bytes to move, lo, hi
.byte $00 ; Interrupt mask reg.
.byte $00 ; Adress control reg.
.byte $00 ; Address control reg.
.code

View File

@ -73,7 +73,7 @@ reu_params: .word $0000 ; Host address, lo, hi
.byte $00 ; Expansion bank no.
.word $0000 ; # bytes to move, lo, hi
.byte $00 ; Interrupt mask reg.
.byte $00 ; Adress control reg.
.byte $00 ; Address control reg.
.code

View File

@ -130,7 +130,7 @@ dowrite:
beq notrunc
jsr scratch
; Complete the the file name. Check for append mode here.
; Complete the file name. Check for append mode here.
notrunc:
lda tmp3 ; Get the mode again
@ -168,7 +168,7 @@ nofile: ; ... else use SA=0 (read)
jsr OPEN
bcs oserror
; Open the the drive command channel and read it
; Open the drive command channel and read it
ldx fnunit
jsr opencmdchannel

View File

@ -31,7 +31,7 @@ FILE* __fastcall__ freopen (const char* name, const char* mode, FILE* f)
** overwritten by _fopen.
*/
if (close (f->f_fd) < 0) {
/* An error occured, errno is already set */
/* An error occurred, errno is already set */
return 0;
}

View File

@ -19,7 +19,7 @@ specval:
; Common subroutine to pop the parameters and put them into core
;
dopop: sta tmp1 ; will loose high byte
dopop: sta tmp1 ; will lose high byte
ldy #0
lda (sp),y
sta ptr2

View File

@ -18,7 +18,7 @@
; Common subroutine to pop the parameters and put them into core
;
dopop: sta tmp1 ; will loose high byte
dopop: sta tmp1 ; will lose high byte
jsr popax ; get s to ptr2
sta ptr2
stx ptr2+1

View File

@ -0,0 +1 @@
; empty file to prevent cbm/cpeeks.s being pulled into the cx16 lib

View File

@ -58,7 +58,7 @@ DbgBreak:
.res 256
DbgStack:
; Swap space for the the C temporaries
; Swap space for the C temporaries
CTemp:
_DbgCS: .res 2 ; sp

View File

@ -89,16 +89,17 @@ putchar:
adc #>(fontdata-$f8)
sta ptr3+1
lda CHARCOLOR
and #1
beq @skip_plane1
lda #LCD_XPOS_PLANE1
clc
adc CURS_X
sta LCD_X
ldy #$f8
ldy #$F8
lda CHARCOLOR
lsr
bcc @delete1
@copylp1:
lda (ptr3),y
eor RVS
@ -106,11 +107,16 @@ putchar:
iny
bne @copylp1
@skip_plane1:
beq @skip_delete1
lda CHARCOLOR
and #2
beq @skip_plane2
@delete1:
lda #$00
@del1:
sta LCD_DATA
iny
bne @del1
@skip_delete1:
lda #LCD_XPOS_PLANE2
clc
@ -121,7 +127,12 @@ putchar:
lda _plotlo,x
sta LCD_Y
ldy #$f8
ldy #$F8
lda CHARCOLOR
and #2
beq @delete2
@copylp2:
lda (ptr3),y
eor RVS
@ -129,7 +140,16 @@ putchar:
iny
bne @copylp2
@skip_plane2:
beq @skip_delete2
@delete2:
lda #$00
@del2:
sta LCD_DATA
iny
bne @del2
@skip_delete2:
pla
tax
ldy CURS_X

View File

@ -17,4 +17,3 @@ _CRC:
lda r2L
ldx r2H
rts

View File

@ -18,44 +18,60 @@
; The idea is to make the smalles possible encrypted loader as decryption
; is very slow. The minimum size is 49 bytes plus a zero byte.
;**********************************
; EXE = $fb68
; EXE = $fb68
;
; .org $0200
; .org $0200
;
; ; 1. force Mikey to be in memory
; stz MAPCTL
; ; 1. force Mikey to be in memory
; 9C F9 FF stz MAPCTL
;
; ; 3. set ComLynx to open collector
; lda #4 ; a = 00000100
; sta SERCTL ; set the ComLynx to open collector
; ; 2. clear palette
; A0 1F ldy #31
; A9 00 lda #0
; 99 A0 FD nextc: sta GCOLMAP, y
; 88 dey
; 10 FA bpl nextc
;
; ; 4. make sure the ROM is powered on
; lda #8 ; a = 00001000
; sta IODAT ; set the ROM power to on
; ; 3. set ComLynx to open collector
; A9 04 lda #4 ; a = 00000100
; 8D 8C FD sta SERCTL ; set the ComLynx to open collector
;
; ; 5. read in secondary exe + 8 bytes from the cart and store it in $f000
; ldx #0 ; x = 0
; ldy #$97 ; y = secondary loader size (151 bytes)
;rloop1: lda RCART0 ; read a byte from the cart
; sta EXE,X ; EXE[X] = a
; inx ; x++
; dey ; y--
; bne rloop1 ; loops until y wraps
; ; 4. set AUDIN to output
; A9 1A lda #$1a ; audin = out, rest = out,
; ; noexp = in, cart addr = out, ext pwd = in
; 8D 8A FD sta IODIR
;
; ; 6. jump to secondary loader
; jmp EXE ; run the secondary loader
; ; 5. set AUDIN to LOW
; A9 0B lda #$0B ; Set AUDIN low
; 85 1A sta $1a ; Save local copy to ZP
; 8D 8B FD sta IODAT
;
; .reloc
; ; 6. read in secondary exe + 8 bytes from the cart
; ; and store it in $f000
; A2 00 ldx #0 ; x = 0
; A0 97 ldy #$97 ; y = secondary loader size (151 bytes)
; AD B2 FC rloop1: lda RCART0 ; read a byte from the cart
; 9D 68 FB sta EXE,X ; EXE[X] = a
; E8 inx ; x++
; 88 dey ; y--
; D0 F6 bne rloop1 ; loops until y wraps
;
; ; 7. jump to secondary loader
; 4C 68 FB jmp EXE
; 00 00 00 00 ; spares
; 00 ; End of encrypted header mark
;
; .reloc
;**********************************
; After compilation, encryption and obfuscation it turns into this.
;**********************************
.byte $ff, $81, $ca, $33, $be, $80, $a2, $c4
.byte $6d, $98, $fe, $8d, $bc, $66, $c0, $7a
.byte $09, $50, $23, $28, $18, $c8, $06, $70
.byte $58, $4f, $1b, $e1, $c7, $90, $08, $cd
.byte $1a, $6e, $5a, $45, $32, $d7, $6d, $c6
.byte $8a, $e5, $d8, $5c, $a0, $e8, $4f, $7a
.byte $5f, $73, $8d, $22
.byte $ff, $b6, $bb, $82, $d5, $9f, $48, $cf
.byte $23, $37, $8e, $07, $38, $f5, $b6, $30
.byte $d6, $2f, $12, $29, $9f, $43, $5b, $2e
.byte $f5, $66, $5c, $db, $93, $1a, $78, $55
.byte $5e, $c9, $0d, $72, $1b, $e9, $d8, $4d
.byte $2f, $e4, $95, $c0, $4f, $7f, $1b, $66
.byte $8b, $a7, $fc, $21
;**********************************
; Now we have the secondary loader

View File

@ -113,7 +113,8 @@ text_bitmap: .res 8*(1+20+1)+1
.rodata
DEFPALETTE: .byte >$011
DEFPALETTE: .byte >$223
.byte >$011
.byte >$34d
.byte >$9af
.byte >$9b8
@ -124,11 +125,11 @@ DEFPALETTE: .byte >$011
.byte >$d5f
.byte >$c53
.byte >$822
.byte >$223
.byte >$484
.byte >$8e5
.byte >$cf5
.byte >$fff
.byte <$223
.byte <$011
.byte <$34d
.byte <$9af
@ -140,7 +141,6 @@ DEFPALETTE: .byte >$011
.byte <$d5f
.byte <$c53
.byte <$822
.byte <$223
.byte <$484
.byte <$8e5
.byte <$cf5
@ -162,6 +162,7 @@ INSTALL:
lda #1
sta TEXTMAGX
sta TEXTMAGY
sta DRAWINDEX
stz BGINDEX
stz DRAWPAGE
stz SWAPREQUEST
@ -418,7 +419,7 @@ cls_sprite:
.word 0
.word $a000 ; 160
.word $6600 ; 102
.byte $00
.byte $11
.code
CLEAR: lda #<cls_sprite
@ -844,11 +845,6 @@ OUTTEXT:
lda TEXTMAGY
sta text_sy+1
lda BGINDEX
beq @L1 ; Choose opaque black sprite?
lda #$04 ; No, choose normal sprite
@L1:
sta text_sprite
lda DRAWINDEX ; Set color
asl
asl
@ -956,7 +952,7 @@ OUTTEXT:
text_coll:
.byte 0
text_sprite:
.byte $00,$90,$20
.byte $04,$90,$20
.addr 0, text_bitmap
text_x:
.word 0

View File

@ -4,5 +4,5 @@
.include "tgi-kernel.inc"
.export tgi_color_black:zp = $00
.export tgi_color_black:zp = $01
.export tgi_color_white:zp = $0F

View File

@ -173,6 +173,7 @@ ScrTabHi:
.byte >(ScrBase + ScrFirstChar + I * ScrollDist)
.endrep
.code
osi_cputfuncs ScrBase, ScrFirstChar, ScrWidth, ScrHeight, \

View File

@ -24,7 +24,7 @@ gotoxy: jsr popa ; Get Y
jsr popa
sta SCRX
; Update adress video ram position when SCRY is modified (update_adscr)
; Update address video ram position when SCRY is modified (update_adscr)
; Fall through
.endproc

View File

@ -379,7 +379,7 @@ out:
tya
tax
lda ptr3 ; XSCHAR needs in A and Y the adress of the string
lda ptr3 ; XSCHAR needs in A and Y the address of the string
ldy ptr3+1
BRK_TELEMON(XSCHAR)
rts

View File

@ -372,7 +372,7 @@ out:
tya
tax
lda ptr3 ; XSCHAR needs in A and Y the adress of the string
lda ptr3 ; XSCHAR needs in A and Y the address of the string
ldy ptr3+1
BRK_TELEMON(XSCHAR)
rts

View File

@ -159,7 +159,7 @@ tgi_clip_sign: .res 1
;----------------------------------------------------------------------------
; Multiplicate value in y/a by dy, then divide by dx.
; Multiply value in y/a by dy, then divide by dx.
;
.code
@ -176,7 +176,7 @@ tgi_clip_sign: .res 1
lda tgi_clip_dy
ldx tgi_clip_dy+1 ; rhs
jsr umul16x16r32 ; Multiplicate
jsr umul16x16r32 ; Multiply
; Move the result of the multiplication into ptr1:ptr2
@ -199,7 +199,7 @@ done: bit tmp1
;----------------------------------------------------------------------------
; Multiplicate value in y/a by dx, then divide by dy.
; Multiply value in y/a by dx, then divide by dy.
;
.code
@ -216,7 +216,7 @@ done: bit tmp1
lda tgi_clip_dx
ldx tgi_clip_dx+1 ; rhs
jsr umul16x16r32 ; Multiplicate
jsr umul16x16r32 ; Multiply
; Move the result of the multiplication into ptr1:ptr2

View File

@ -33,7 +33,7 @@ _tgi_imulround:
; ASM callable entry point
tgi_imulround:
; Multiplicate
; Multiply
jsr imul16x16r32

View File

@ -79,9 +79,9 @@ GetProcessedCoord:
jsr GetOp
; Multiplicate with the scale factor.
; Multiply with the scale factor.
jmp tgi_imulround ; Multiplicate, round and scale
jmp tgi_imulround ; Multiply, round and scale
;----------------------------------------------------------------------------
; Add the base coordinate with offset in Y to the value in A/X
@ -133,7 +133,7 @@ GetProcessedCoord:
.code
.proc _tgi_vectorchar
; Multiplicate the char value by two and save into Y
; Multiply the char value by two and save into Y
asl a
tay

View File

@ -154,7 +154,7 @@ endif
# Lists of subdirectories
# disasm depends on cpp
DIRLIST = tutorial geos atari2600 atari5200 apple2 gamate supervision sym1 cbm
DIRLIST = tutorial geos atari2600 atari5200 apple2 gamate lynx supervision sym1 cbm
# --------------------------------------------------------------------------
# Lists of executables
@ -199,7 +199,8 @@ EXELIST_atmos = \
ascii \
hello \
mandelbrot \
sieve
sieve \
tgidemo
EXELIST_bbc = \
notavailable
@ -321,7 +322,7 @@ EXELIST_telestrat = \
hello \
mandelbrot \
sieve \
# tgidemo
tgidemo
EXELIST_vic20 = \
ascii \

View File

@ -53,7 +53,7 @@ test.s: test.grc
$(GRC) -s test.s test.grc
vlir.cvt: vlir.grc vlir0.s vlir1.s vlir2.s
# using seperate calls here for demonstration purposes:
# using separate calls here for demonstration purposes:
$(GRC) -t $(SYS) -s vlir.s vlir.grc
$(AS) -t $(SYS) vlir.s
$(AS) -t $(SYS) vlir0.s

59
samples/lynx/Makefile Normal file
View File

@ -0,0 +1,59 @@
# Run 'make SYS=<target>'; or, set a SYS env.
# var. to build for another target system.
SYS ?= lynx
# Just the usual way to find out if we're
# using cmd.exe to execute make rules.
ifneq ($(shell echo),)
CMD_EXE = 1
endif
ifdef CMD_EXE
NULLDEV = nul:
DEL = -del /f
else
NULLDEV = /dev/null
DEL = $(RM)
endif
ifdef CC65_HOME
AS = $(CC65_HOME)/bin/ca65
CC = $(CC65_HOME)/bin/cc65
CL = $(CC65_HOME)/bin/cl65
LD = $(CC65_HOME)/bin/ld65
else
AS := $(if $(wildcard ../../bin/ca65*),../../bin/ca65,ca65)
CC := $(if $(wildcard ../../bin/cc65*),../../bin/cc65,cc65)
CL := $(if $(wildcard ../../bin/cl65*),../../bin/cl65,cl65)
LD := $(if $(wildcard ../../bin/ld65*),../../bin/ld65,ld65)
endif
EXELIST_lynx = \
hello.lnx \
mandelbrot.lnx \
tgidemo.lnx
.PHONY: samples clean
ifneq ($(EXELIST_$(SYS)),)
samples: $(EXELIST_$(SYS))
else
samples:
# recipe used to skip systems that will not work with any program in this dir
ifeq ($(MAKELEVEL),0)
@echo "info: Lynx tests not available for" $(SYS)
else
# Suppress the "nothing to be done for 'samples' message.
@echo "" > $(NULLDEV)
endif
endif
.SUFFIXES:
.SUFFIXES: .c .lnx
%.lnx : %.c
$(CL) -t $(SYS) -Oris -m $*.map -o $@ $<
clean:
@$(DEL) *.o *.map *.lnx 2>$(NULLDEV)

43
samples/lynx/hello.c Normal file
View File

@ -0,0 +1,43 @@
/* Atari Lynx version of samples/hello.c, using TGI instead of conio */
#include <tgi.h>
/*****************************************************************************/
/* Data */
/*****************************************************************************/
static const char Text[] = "Hello world!";
/*****************************************************************************/
/* Code */
/*****************************************************************************/
void main (void)
{
unsigned int XMax, YMax;
tgi_install (tgi_static_stddrv);
tgi_init ();
/* Set screen color. */
tgi_setcolor (TGI_COLOR_WHITE);
/* Clear the screen. */
tgi_clear();
/* Ask for the screen size. */
XMax = tgi_getmaxx ();
YMax = tgi_getmaxy ();
/* Draw a frame around the screen. */
tgi_line (0, 0, XMax, 0);
tgi_lineto (XMax, YMax);
tgi_lineto (0, YMax);
tgi_lineto (0, 0);
/* Write the greeting in the middle of the screen. */
tgi_outtextxy ((tgi_getxres () - tgi_gettextwidth (Text)) / 2,
(tgi_getyres () - tgi_gettextheight (Text)) / 2, Text);
}

86
samples/lynx/mandelbrot.c Normal file
View File

@ -0,0 +1,86 @@
/*****************************************************************************\
** mandelbrot sample program for Atari Lynx **
** **
** (w) 2002 by groepaz/hitmen, TGI support by Stefan Haubenthal **
\*****************************************************************************/
#include <stdlib.h>
#include <tgi.h>
/* Graphics definitions */
#define SCREEN_X (tgi_getxres())
#define SCREEN_Y (tgi_getyres())
#define MAXCOL (tgi_getcolorcount())
#define maxiterations 32
#define fpshift (10)
#define tofp(_x) ((_x)<<fpshift)
#define fromfp(_x) ((_x)>>fpshift)
#define fpabs(_x) (abs(_x))
#define mulfp(_a,_b) ((((signed long)_a)*(_b))>>fpshift)
#define divfp(_a,_b) ((((signed long)_a)<<fpshift)/(_b))
/* Use static local variables for speed */
#pragma static-locals (1);
static void mandelbrot (signed short x1, signed short y1, signed short x2,
signed short y2)
{
/* */
register signed short r, r1, i;
register signed short xs, ys, xx, yy;
register signed short x, y;
register unsigned char count;
register unsigned char maxcol = MAXCOL;
/* Calc stepwidth */
xs = ((x2 - x1) / (SCREEN_X));
ys = ((y2 - y1) / (SCREEN_Y));
yy = y1;
for (y = 0; y < (SCREEN_Y); y++) {
yy += ys;
xx = x1;
for (x = 0; x < (SCREEN_X); x++) {
xx += xs;
/* Do iterations */
r = 0;
i = 0;
for (count = 0; (count < maxiterations) &&
(fpabs (r) < tofp (2)) && (fpabs (i) < tofp (2));
++count) {
r1 = (mulfp (r, r) - mulfp (i, i)) + xx;
/* i = (mulfp(mulfp(r,i),tofp(2)))+yy; */
i = (((signed long) r * i) >> (fpshift - 1)) + yy;
r = r1;
}
if (count == maxiterations) {
tgi_setcolor (0);
} else {
tgi_setcolor (count % maxcol);
}
/* Set pixel */
tgi_setpixel (x, y);
}
}
}
void main (void)
{
/* Install the graphics driver */
tgi_install (tgi_static_stddrv);
/* Initialize graphics */
tgi_init ();
tgi_clear ();
/* Calc mandelbrot set */
mandelbrot (tofp (-2), tofp (-2), tofp (2), tofp (2));
}

179
samples/lynx/tgidemo.c Normal file
View File

@ -0,0 +1,179 @@
/* Tgidemo modified for the Atari Lynx.
**
** Press any of the Lynx's option buttons to go to the next screen.
*/
#include <cc65.h>
#include <conio.h>
#include <tgi.h>
#include <time.h>
#define COLOR_BACK TGI_COLOR_BLACK
#define COLOR_FORE TGI_COLOR_WHITE
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/* Driver stuff */
static unsigned MaxX;
static unsigned MaxY;
static unsigned AspectRatio;
/*****************************************************************************/
/* Code */
/*****************************************************************************/
/* The Lynx draws too fast. This function delays
** the drawing so that we can watch it.
*/
static void wait (unsigned char ticks)
{
clock_t T = clock () + ticks;
while (clock () < T) {}
}
static void DoCircles (void)
{
unsigned char I;
unsigned char Color = COLOR_BACK;
const unsigned X = MaxX / 2;
const unsigned Y = MaxY / 2;
const unsigned Limit = (X < Y) ? Y : X;
tgi_setcolor (COLOR_FORE);
tgi_clear ();
tgi_line (0, 0, MaxX, MaxY);
tgi_line (0, MaxY, MaxX, 0);
while (!kbhit ()) {
Color = (Color == COLOR_FORE) ? COLOR_BACK : COLOR_FORE;
tgi_setcolor (Color);
for (I = 10; I <= Limit; I += 10) {
tgi_ellipse (X, Y, I, tgi_imulround (I, AspectRatio));
wait (9);
}
}
cgetc ();
}
static void DoCheckerboard (void)
{
unsigned X, Y;
unsigned char Color = COLOR_BACK;
tgi_clear ();
while (1) {
for (Y = 0; Y <= MaxY - 2; Y += 10) {
for (X = 0; X <= MaxX; X += 10) {
Color = (Color == COLOR_FORE) ? COLOR_BACK : COLOR_FORE;
tgi_setcolor (Color);
tgi_bar (X, Y, X+9, Y+9);
if (kbhit ()) {
cgetc ();
return;
}
wait (1);
}
Color = Color == COLOR_FORE ? COLOR_BACK : COLOR_FORE;
}
Color = Color == COLOR_FORE ? COLOR_BACK : COLOR_FORE;
}
}
static void DoDiagram (void)
{
int XOrigin, YOrigin;
int Amp;
int X, Y;
unsigned I;
tgi_setcolor (COLOR_FORE);
tgi_clear ();
/* Determine zero and amplitude */
YOrigin = MaxY / 2;
XOrigin = 10;
Amp = (MaxY - 19) / 2;
/* Y axis */
tgi_line (XOrigin, 10, XOrigin, MaxY-10);
tgi_line (XOrigin-2, 12, XOrigin, 10);
tgi_lineto (XOrigin+2, 12);
/* X axis */
tgi_line (XOrigin, YOrigin, MaxX-10, YOrigin);
tgi_line (MaxX-12, YOrigin-2, MaxX-10, YOrigin);
tgi_lineto (MaxX-12, YOrigin+2);
/* Sine */
tgi_gotoxy (XOrigin, YOrigin);
for (I = 0; I <= 360; ++I) {
/* Calculate the next points */
X = (int)(((long)(MaxX - 19) * I) / 360);
Y = (int)(((long)Amp * -_sin (I)) / 256);
/* Draw the line */
tgi_lineto (XOrigin + X, YOrigin + Y);
}
cgetc ();
}
static void DoLines (void)
{
unsigned X;
const unsigned Min = (MaxX < MaxY) ? MaxX : MaxY;
tgi_setcolor (COLOR_FORE);
tgi_clear ();
for (X = 0; X <= Min; X += 10) {
tgi_line (0, 0, Min, X);
tgi_line (0, 0, X, Min);
tgi_line (Min, Min, 0, Min-X);
tgi_line (Min, Min, Min-X, 0);
wait (9);
}
cgetc ();
}
void main (void)
{
/* Install the driver */
tgi_install (tgi_static_stddrv);
tgi_init ();
/* Get stuff from the driver */
MaxX = tgi_getmaxx ();
MaxY = tgi_getmaxy ();
AspectRatio = tgi_getaspectratio ();
/* Do graphics stuff */
DoCircles ();
DoCheckerboard ();
DoDiagram ();
DoLines ();
}

View File

@ -237,7 +237,7 @@ void main (void)
/* The linker makes sure that the call to foo() ends up at the right mem
** addr. However it's up to user to make sure that the - right - overlay
** is actually loaded before making the the call.
** is actually loaded before making the call.
*/
foo ();
}

View File

@ -112,7 +112,7 @@ void main (void)
/* The linker makes sure that the call to foo() ends up at the right mem
** addr. However it's up to user to make sure that the - right - overlay
** is actually loaded before making the the call.
** is actually loaded before making the call.
*/
foo ();
}

View File

@ -128,7 +128,7 @@ Platforms: Runs on all platforms that have TGI support:
=============================================================================
Platform specific samples follow:
Platform-specific samples follow:
atari 2600:
-----------
@ -198,6 +198,27 @@ Name: nachtm
Description: Plays "Eine kleine Nachtmusik" by Wolfgang Amadeus Mozart.
-----------------------------------------------------------------------------
lynx:
-----
These programs are adapted for the Atari Lynx because its library has no conio
output or stdio.
Name: hello
Description: A nice "Hello world" type program that uses the TGI graphics
library for output.
Name: mandelbrot
Description: A mandelbrot demo using integer arithmetic. The demo was
written by groepaz, and converted to cc65 using TGI graphics
by Stefan Haubenthal.
Name: tgidemo
Description: Shows some of the graphics capabilities of the "Tiny Graphics
Interface".
-----------------------------------------------------------------------------
sym1:
-----

View File

@ -32,7 +32,7 @@ else
endif
EXELIST_sym1 = \
symHello.bin symTiny.bin symDisplay.bin symIO.bin symNotepad.bin
symHello.bin symTiny.bin symDisplay.bin symIO.bin symNotepad.bin symExtendedMemory.bin
ifneq ($(EXELIST_$(SYS)),)
samples: $(EXELIST_$(SYS))
@ -64,9 +64,14 @@ symIO.bin: symIO.c
symNotepad.bin: symNotepad.c
$(CL) -t sym1 -C sym1-32k.cfg -O -o symNotepad.bin symNotepad.c
symExtendedMemory.bin: symExtendedMemory.c
$(CL) -t sym1 -C sym1-32k.cfg -O -o symExtendedMemory.bin symExtendedMemory.c
clean:
@$(DEL) symHello.bin 2>$(NULLDEV)
@$(DEL) symTiny.bin 2>$(NULLDEV)
@$(DEL) symDisplay.bin 2>$(NULLDEV)
@$(DEL) symIO.bin 2>$(NULLDEV)
@$(DEL) symNotepad.bin 2>$(NULLDEV)
@$(DEL) symExtendedMemory.bin 2>$(NULLDEV)

View File

@ -0,0 +1,101 @@
// --------------------------------------------------------------------------
// Sym-1 Extended Memory
//
// Wayne Parham
//
// wayne@parhamdata.com
// --------------------------------------------------------------------------
//
// Note: This program examines memory above the monitor ROM (8000-8FFF) to
// Determine what, if any, memory is available. It then adds whatever
// 4K segments it finds to the heap.
//
// Memory Segment Remark
// 0x9000 Usually available
// 0xA000 System I/O, always unavailable
// 0xB000 Used by RAE, but normally available
// 0xC000 Used by BASIC, normally unavailable
// 0xD000 Used by BASIC, normally unavailable
// 0xE000 Used by RAE, but normally available
// 0xF000 Normally available, but only to FF7F
//
// --------------------------------------------------------------------------
#include <sym1.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define STD_MEM 0x7FFF // Last address of standard memory
#define SEGMENT 0x9000 // First 4K segment of extended memory
#define SEG_END 0x0FFF // Last location of segment
#define BLOCK_SIZE 0x1000 // Size of segment
#define TOP_END 0x0F7F // Last location of memory
#define TOP_SIZE 0x0F80 // Size of top segment
#define UNAVAILABLE 0xA000 // System I/O area
int main (void) {
int error = 0;
unsigned heap_size = 0x0000;
char* segment = (char*) SEGMENT;
printf ( "Analyzing memory.\n\n" );
heap_size = _heapmemavail();
printf ( "Main memory has %u bytes available.\n", heap_size );
if ( heap_size > STD_MEM ) {
printf ( "Extended memory already installed.\n" );
} else {
while ( (int) segment < 0xEFFF ) { // Iterate through 4K memory blocks
if( (int) segment != UNAVAILABLE ) {
segment[0] = 0x00; // Check beginning of segment
if ( segment[0] != 0x00 )
error = 1;
segment[0] = 0xFF;
if ( segment[0] != 0xFF )
error = 1;
segment[SEG_END] = 0x00; // Check end of segment
if ( segment[SEG_END] != 0x00 )
error = 1;
segment[SEG_END] = 0xFF;
if ( segment[SEG_END] != 0xFF )
error = 1;
if ( ! error ) { // If memory found, add to the heap
printf ( "Memory found at location %p, ", segment );
_heapadd ( segment, BLOCK_SIZE );
heap_size = _heapmemavail();
printf( "so the system now has %u bytes available.\n", heap_size );
} else {
error = 0;
}
}
segment += 0x1000; // Increment to next segment
}
segment[0] = 0x00; // Check beginning of top memory segment
if ( segment[0] != 0x00 )
error = 1;
segment[0] = 0xFF;
if ( segment[0] != 0xFF )
error = 1;
segment[TOP_END] = 0x00; // Check end of usable memory
if ( segment[TOP_END] != 0x00 )
error = 1;
segment[TOP_END] = 0xFF;
if ( segment[TOP_END] != 0xFF )
error = 1;
if ( ! error ) { // If memory found, add to the heap
printf ( "Memory found at location %p, ", segment );
_heapadd ( segment, TOP_SIZE );
heap_size = _heapmemavail();
printf( "so the system now has %u bytes available.\n", heap_size );
}
}
puts ("\nEnjoy your day!\n");
return 0;
}

View File

@ -138,21 +138,21 @@ int main (void) {
}
else
{
for ( l = 0; l <= heap_size; l++ ) {
buffer[l] = tapio[l];
}
for ( l = 0; l <= heap_size; l++ ) {
buffer[l] = tapio[l];
}
p = strlen ( buffer );
p = strlen ( buffer );
putchar ( '\r' );
for ( l = 0; l < 25; l++ ) {
putchar ( '\n' );
}
puts ("===================== Sym-1 Notepad ====================\n");
putchar ( '\r' );
for ( l = 0; l < 25; l++ ) {
putchar ( '\n' );
}
puts ("===================== Sym-1 Notepad ====================\n");
for ( l = 0; l <= p; l++ ) {
putchar ( buffer[l] );
}
for ( l = 0; l <= p; l++ ) {
putchar ( buffer[l] );
}
}
}
else if ( c == 0x03 ) { // Clear

View File

@ -68,7 +68,7 @@ static void DoWarning (void)
static void DoCircles (void)
{
static const unsigned char Palette[2] = { TGI_COLOR_WHITE, TGI_COLOR_ORANGE };
static const unsigned char Palette[2] = { TGI_COLOR_WHITE, TGI_COLOR_BLUE };
unsigned char I;
unsigned char Color = COLOR_BACK;
const unsigned X = MaxX / 2;

View File

@ -119,6 +119,7 @@ endif # CMD_EXE
zip:
@cd .. && zip cc65 bin/*
@echo 'https://github.com/cc65/cc65/commits/'$(word 2,$(BUILD_ID))|zip -zq ../cc65
define OBJS_template

View File

@ -1708,7 +1708,7 @@ ExprNode* GenLiteralExpr (long Val)
ExprNode* GenLiteral0 (void)
/* Return an expression tree that encodes the the number zero */
/* Return an expression tree that encodes the number zero */
{
return GenLiteralExpr (0);
}

View File

@ -81,7 +81,7 @@ ExprNode* GenLiteralExpr (long Val);
/* Return an expression tree that encodes the given literal value */
ExprNode* GenLiteral0 (void);
/* Return an expression tree that encodes the the number zero */
/* Return an expression tree that encodes the number zero */
ExprNode* GenSymExpr (struct SymEntry* Sym);
/* Return an expression node that encodes the given symbol */

View File

@ -429,7 +429,7 @@ void ReleaseFullLineInfo (Collection* LineInfos)
/* Walk over all entries */
for (I = 0; I < CollCount (LineInfos); ++I) {
/* Release the the line info */
/* Release the line info */
ReleaseLineInfo (CollAt (LineInfos, I));
}

View File

@ -637,7 +637,7 @@ void MacUndef (const StrBuf* Name, unsigned char Style)
static int MacExpand (void* Data)
/* If we're currently expanding a macro, set the the scanner token and
/* If we're currently expanding a macro, set the scanner token and
** attribute to the next value and return true. If we are not expanding
** a macro, return false.
*/

View File

@ -212,6 +212,10 @@ static void SetSys (const char* Sys)
NewSymbol ("__ATARI5200__", 1);
break;
case TGT_ATARI7800:
NewSymbol ("__ATARI7800__", 1);
break;
case TGT_ATARI:
NewSymbol ("__ATARI__", 1);
break;

View File

@ -711,7 +711,7 @@ static void StudyMul (ExprNode* Expr, ExprDesc* D)
*/
if (ED_IsConst (D) && ED_IsValid (&Right)) {
/* Multiplicate both, result goes into Right */
/* Multiply both, result goes into Right */
ED_Mul (&Right, D);
/* Move result into D */
@ -719,7 +719,7 @@ static void StudyMul (ExprNode* Expr, ExprDesc* D)
} else if (ED_IsConst (&Right) && ED_IsValid (D)) {
/* Multiplicate both */
/* Multiply both */
ED_Mul (D, &Right);
} else {

View File

@ -93,6 +93,7 @@
<ClInclude Include="cc65\hexval.h" />
<ClInclude Include="cc65\ident.h" />
<ClInclude Include="cc65\incpath.h" />
<ClInclude Include="cc65\initdata.h" />
<ClInclude Include="cc65\input.h" />
<ClInclude Include="cc65\lineinfo.h" />
<ClInclude Include="cc65\litpool.h" />
@ -170,6 +171,7 @@
<ClCompile Include="cc65\hexval.c" />
<ClCompile Include="cc65\ident.c" />
<ClCompile Include="cc65\incpath.c" />
<ClCompile Include="cc65\initdata.c" />
<ClCompile Include="cc65\input.c" />
<ClCompile Include="cc65\lineinfo.c" />
<ClCompile Include="cc65\litpool.c" />

View File

@ -156,19 +156,8 @@ void DoIncDecBitField (ExprDesc* Expr, long Val, unsigned KeepResult)
unsigned ChunkFlags;
const Type* ChunkType;
/* If the bit-field fits within one byte, do the following operations
** with bytes.
*/
if ((Expr->Type->A.B.Width - 1U) / CHAR_BITS ==
(Expr->Type->A.B.Offs + Expr->Type->A.B.Width - 1U) / CHAR_BITS) {
ChunkType = GetUnderlyingType (Expr->Type);
} else {
/* We use the declarartion integer type as the chunk type.
** Note: A bit-field will not occupy bits located in bytes more than
** that of its declaration type in cc65. So this is OK.
*/
ChunkType = Expr->Type + 1;
}
/* Determine the type to operate on the whole byte chunk containing the bit-field */
ChunkType = GetBitFieldChunkType (Expr->Type);
/* Determine code generator flags */
Flags = TypeOf (Expr->Type) | CF_FORCECHAR;
@ -254,19 +243,8 @@ static void OpAssignBitField (const GenDesc* Gen, ExprDesc* Expr, const char* Op
ED_Init (&Expr2);
Expr2.Flags |= Expr->Flags & E_MASK_KEEP_SUBEXPR;
/* If the bit-field fits within one byte, do the following operations
** with bytes.
*/
if ((Expr->Type->A.B.Width - 1U) / CHAR_BITS ==
(Expr->Type->A.B.Offs + Expr->Type->A.B.Width - 1U) / CHAR_BITS) {
ChunkType = GetUnderlyingType (Expr->Type);
} else {
/* We use the declarartion integer type as the chunk type.
** Note: A bit-field will not occupy bits located in bytes more than
** that of its declaration type in cc65. So this is OK.
*/
ChunkType = Expr->Type + 1;
}
/* Determine the type to operate on the whole byte chunk containing the bit-field */
ChunkType = GetBitFieldChunkType (Expr->Type);
/* Determine code generator flags */
Flags = TypeOf (Expr->Type) | CF_FORCECHAR;
@ -620,8 +598,8 @@ void OpAssign (const GenDesc* Gen, ExprDesc* Expr, const char* Op)
if (IsClassStruct (ltype)) {
/* Copy the struct or union by value */
CopyStruct (Expr, &Expr2);
} else if (IsTypeBitField (ltype)) {
/* Special care is needed for bit-field 'op=' */
} else if (IsTypeFragBitField (ltype)) {
/* Special care is needed for bit-fields if they don't fit in full bytes */
OpAssignBitField (Gen, Expr, Op);
} else {
/* Normal straight 'op=' */

View File

@ -95,7 +95,7 @@ void FreeCaseNodeColl (Collection* Nodes)
int SearchCaseNode (const Collection* Nodes, unsigned char Key, int* Index)
/* Search for a node in the given collection. If the node has been found,
** set Index to the index of the node and return true. If the node was not
** found, set Index the the insertion position of the node and return
** found, set Index the insertion position of the node and return
** false.
*/
{

View File

@ -116,7 +116,7 @@ void FreeCaseNodeColl (Collection* Nodes);
int SearchCaseNode (const Collection* Nodes, unsigned char Key, int* Index);
/* Search for a node in the given collection. If the node has been found,
** set Index to the index of the node and return true. If the node was not
** found, set Index the the insertion position of the node and return
** found, set Index to the insertion position of the node and return
** false.
*/

View File

@ -33,6 +33,7 @@
#include <inttypes.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
@ -42,7 +43,7 @@
#include "addrsize.h"
#include "check.h"
#include "cpu.h"
#include "inttypes.h"
#include "shift.h"
#include "strbuf.h"
#include "xmalloc.h"
#include "xsprintf.h"
@ -689,7 +690,7 @@ void g_restore_regvars (int StackOffs, int RegOffs, unsigned Bytes)
void g_getimmed (unsigned Flags, unsigned long Val, long Offs)
void g_getimmed (unsigned Flags, uintptr_t Val, long Offs)
/* Load a constant into the primary register */
{
unsigned char B1, B2, B3, B4;
@ -1409,7 +1410,7 @@ static unsigned g_intpromotion (unsigned flags)
unsigned g_typeadjust (unsigned lhs, unsigned rhs)
/* Adjust the integer operands before doing a binary operation. lhs is a flags
** value, that corresponds to the value on TOS, rhs corresponds to the value
** in (e)ax. The return value is the the flags value for the resulting type.
** in (e)ax. The return value is the flags value for the resulting type.
*/
{
/* Get the type spec from the flags */
@ -4394,7 +4395,7 @@ void g_res (unsigned n)
void g_defdata (unsigned flags, unsigned long val, long offs)
void g_defdata (unsigned flags, uintptr_t val, long offs)
/* Define data with the size given in flags */
{
if (flags & CF_CONST) {
@ -4403,15 +4404,15 @@ void g_defdata (unsigned flags, unsigned long val, long offs)
switch (flags & CF_TYPEMASK) {
case CF_CHAR:
AddDataLine ("\t.byte\t$%02lX", val & 0xFF);
AddDataLine ("\t.byte\t$%02"PRIXPTR, val & 0xFF);
break;
case CF_INT:
AddDataLine ("\t.word\t$%04lX", val & 0xFFFF);
AddDataLine ("\t.word\t$%04"PRIXPTR, val & 0xFFFF);
break;
case CF_LONG:
AddDataLine ("\t.dword\t$%08lX", val & 0xFFFFFFFF);
AddDataLine ("\t.dword\t$%08"PRIXPTR, val & 0xFFFFFFFF);
break;
default:
@ -4560,110 +4561,268 @@ void g_initstatic (unsigned InitLabel, unsigned VarLabel, unsigned Size)
void g_testbitfield (unsigned Flags, unsigned BitOffs, unsigned BitWidth)
/* Test bit-field in ax. */
/* Test bit-field in primary. */
{
unsigned EndBit = BitOffs + BitWidth;
/* Since the end is inclusive and cannot be negative here, we subtract 1 from the sum */
unsigned MSBit = BitOffs + BitWidth - 1U;
unsigned Bytes = MSBit / CHAR_BITS + 1U - BitOffs / CHAR_BITS;
unsigned HeadMask = (0xFF << (BitOffs % CHAR_BITS)) & 0xFF;
unsigned TailMask = ((1U << (MSBit % CHAR_BITS + 1U)) - 1U) & 0xFF;
unsigned UntestedBytes = ((1U << Bytes) - 1U) << (BitOffs / CHAR_BITS);
/* We don't use these flags for now. Could CF_NOKEEP be potentially interesting? */
Flags &= ~CF_STYPEMASK;
/* If we need to do a test, then we avoid shifting (ASR only shifts one bit at a time,
** so is slow) and just AND with the appropriate mask, then test the result of that.
** so is slow) and just AND the head and tail bytes with the appropriate mask, then
** OR the results with the rest bytes.
*/
/* Avoid overly large shift on host platform. */
if (EndBit == sizeof (unsigned long) * CHAR_BIT) {
g_and (Flags | CF_CONST, (~0UL << BitOffs));
} else {
g_and (Flags | CF_CONST, ((1UL << EndBit) - 1) & (~0UL << BitOffs));
if (Bytes == 1) {
HeadMask = TailMask = HeadMask & TailMask;
}
/* TODO: When long bit-fields are supported, an optimization to test only 3 bytes when
** EndBit <= 24 is possible.
*/
g_test (Flags | CF_CONST);
/* Get the head byte */
switch (BitOffs / CHAR_BITS) {
case 0:
if (HeadMask == 0xFF && Bytes == 1) {
AddCodeLine ("tax");
UntestedBytes &= ~0x1;
}
break;
case 1:
if (HeadMask != 0xFF || TailMask == 0xFF) {
AddCodeLine ("txa");
UntestedBytes &= ~0x2;
}
break;
case 2:
if (HeadMask != 0xFF || TailMask == 0xFF) {
AddCodeLine ("lda sreg");
UntestedBytes &= ~0x4;
}
break;
case 3:
/* In this case we'd have HeadMask == TailMask and only 1 byte, but anyways... */
if (HeadMask != 0xFF || TailMask == 0xFF) {
AddCodeLine ("lda sreg+1");
UntestedBytes &= ~0x8;
}
break;
default:
break;
}
/* Keep in mind that the head is NOT always "Byte 0" */
if (HeadMask != 0xFF) {
AddCodeLine ("and #$%02X", HeadMask);
/* Abuse the "Byte 0" flag so that this head content will be saved by the routine */
UntestedBytes |= 0x1;
}
/* If there is only 1 byte to test, we have done with it */
if (Bytes == 1) {
return;
}
/* Handle the tail byte */
if (TailMask != 0xFF) {
/* If we have to do any more masking operation, register A will be used for that,
** and its current content in it must be saved.
*/
if (UntestedBytes & 0x1) {
AddCodeLine ("sta tmp1");
}
/* Test the tail byte */
switch (MSBit / CHAR_BITS) {
case 1:
AddCodeLine ("txa");
UntestedBytes &= ~0x2;
break;
case 2:
AddCodeLine ("lda sreg");
UntestedBytes &= ~0x4;
break;
case 3:
AddCodeLine ("lda sreg+1");
UntestedBytes &= ~0x8;
break;
default:
break;
}
AddCodeLine ("and #$%02X", TailMask);
if (UntestedBytes & 0x1) {
AddCodeLine ("ora tmp1");
}
}
/* OR the rest bytes together, which could never need masking */
if (UntestedBytes & 0x2) {
AddCodeLine ("stx tmp1");
AddCodeLine ("ora tmp1");
}
if (UntestedBytes & 0x4) {
AddCodeLine ("ora sreg");
}
if (UntestedBytes & 0x8) {
AddCodeLine ("ora sreg+1");
}
}
void g_extractbitfield (unsigned Flags, unsigned FullWidthFlags, int IsSigned,
unsigned BitOffs, unsigned BitWidth)
/* Extract bits from bit-field in ax. */
/* Extract bits from bit-field in primary. */
{
unsigned EndBit = BitOffs + BitWidth;
unsigned long ZeroExtendMask = 0; /* Zero if we don't need to zero-extend. */
/* Shift right by the bit offset; no code is emitted if BitOffs is zero */
g_asr (Flags | CF_CONST, BitOffs);
/* Since we have now shifted down, we could do char ops when the width fits in a char, but we
** also need to clear (or set) the high byte since we've been using CF_FORCECHAR up to now.
*/
unsigned Mask = (1U << BitWidth) - 1;
/* To zero-extend, we will and by the width if the field doesn't end on a char or
** int boundary. If it does end on a boundary, then zeros will have already been shifted in,
** but we need to clear the high byte for char. g_and emits no code if the mask is all ones.
** This is here so the signed and unsigned branches can use it.
*/
unsigned ZeroExtendMask = 0; /* Zero if we don't need to zero-extend. */
if (EndBit == CHAR_BITS) {
/* We need to clear the high byte, since CF_FORCECHAR was set. */
ZeroExtendMask = 0xFF;
} else if (EndBit != INT_BITS) {
ZeroExtendMask = (1U << BitWidth) - 1;
} else if (EndBit != INT_BITS && EndBit != LONG_BITS) {
ZeroExtendMask = shl_l (1UL, BitWidth) - 1UL;
}
/* Handle signed bit-fields. */
if (IsSigned) {
/* Save .A because the sign-bit test will destroy it. */
AddCodeLine ("tay");
/* Check sign bit */
unsigned SignBitPos = BitWidth - 1U;
unsigned SignBitByte = SignBitPos / CHAR_BITS;
unsigned SignBitPosInByte = SignBitPos % CHAR_BITS;
unsigned SignBitMask = 1U << SignBitPosInByte;
/* Move the correct byte to .A. This can be only .X for now,
** but more cases will be needed to support long.
*/
switch (SignBitByte) {
case 0:
break;
case 1:
AddCodeLine ("txa");
break;
default:
FAIL ("Invalid Byte for sign bit");
}
/* Test the sign bit */
AddCodeLine ("and #$%02X", SignBitMask);
unsigned ZeroExtendLabel = GetLocalLabel ();
AddCodeLine ("beq %s", LocalLabelName (ZeroExtendLabel));
/* Get back .A and sign-extend if required; operating on the full result needs
** to sign-extend into the high byte, too.
*/
AddCodeLine ("tya");
g_or (FullWidthFlags | CF_CONST, ~Mask);
/* We can generate a branch, instead of a jump, here because we know
** that only a few instructions will be put between here and where
** DoneLabel will be defined.
*/
unsigned DoneLabel = GetLocalLabel ();
g_branch (DoneLabel);
/* Get back .A, then zero-extend. We need to duplicate the TYA, rather than move it before
** the branch to share with the other label, because TYA changes some condition codes.
*/
g_defcodelabel (ZeroExtendLabel);
AddCodeLine ("tya");
/* Zero the upper bits, the same as the unsigned path. */
if (ZeroExtendMask != 0) {
g_and (FullWidthFlags | CF_CONST, ZeroExtendMask);
}
/* The universal trick is:
** x = bits & bit_mask
** m = 1 << (bit_width - 1)
** r = (x ^ m) - m
** which works for long as well.
*/
g_defcodelabel (DoneLabel);
if (SignBitByte + 1U == sizeofarg (FullWidthFlags)) {
/* We can just sign-extend on the high byte if it is the only affected one */
unsigned char SignBitMask = (1UL << SignBitPosInByte) & 0xFF;
unsigned char Mask = ((2UL << (SignBitPos % CHAR_BITS)) - 1UL) & 0xFF;
/* Move the correct byte to .A */
switch (SignBitByte) {
case 0:
break;
case 1:
AddCodeLine ("tay");
AddCodeLine ("txa");
break;
case 3:
AddCodeLine ("tay");
AddCodeLine ("lda sreg+1");
break;
default:
FAIL ("Invalid Byte for sign bit");
}
/* Use .A to do the ops on the correct byte */
AddCodeLine ("and #$%02X", Mask);
AddCodeLine ("eor #$%02X", SignBitMask);
AddCodeLine ("sec");
AddCodeLine ("sbc #$%02X", SignBitMask);
/* Move the correct byte from .A */
switch (SignBitByte) {
case 0:
break;
case 1:
AddCodeLine ("tax");
AddCodeLine ("tya");
break;
case 3:
AddCodeLine ("sta sreg+1");
AddCodeLine ("tya");
break;
default:
FAIL ("Invalid Byte for sign bit");
}
} else {
unsigned long SignBitMask = 1UL << SignBitPos;
unsigned long Mask = (2UL << SignBitPos) - 1UL;
g_and (FullWidthFlags | CF_CONST, Mask);
g_xor (FullWidthFlags | CF_CONST, SignBitMask);
g_dec (FullWidthFlags | CF_CONST, SignBitMask);
}
} else {
unsigned char SignBitMask = (1UL << SignBitPosInByte) & 0xFF;
unsigned ZeroExtendLabel = GetLocalLabel ();
/* Save .A because the sign-bit test will destroy it. */
AddCodeLine ("tay");
/* Move the correct byte to .A */
switch (SignBitByte) {
case 0:
break;
case 1:
AddCodeLine ("txa");
break;
case 3:
AddCodeLine ("lda sreg+1");
break;
default:
FAIL ("Invalid Byte for sign bit");
}
/* Test the sign bit */
AddCodeLine ("and #$%02X", SignBitMask);
AddCodeLine ("beq %s", LocalLabelName (ZeroExtendLabel));
if (SignBitByte + 1U == sizeofarg (FullWidthFlags)) {
/* We can just sign-extend on the high byte if it is the only affected one */
unsigned char Mask = ~((2UL << (SignBitPos % CHAR_BITS)) - 1UL) & 0xFF;
/* Use .A to do the ops on the correct byte */
switch (SignBitByte) {
case 0:
AddCodeLine ("tya");
AddCodeLine ("ora #$%02X", Mask);
/* We could jump over the following tya instead, but that wouldn't be faster
** than taking this extra tay and then the tya.
*/
AddCodeLine ("tay");
break;
case 1:
AddCodeLine ("txa");
AddCodeLine ("ora #$%02X", Mask);
AddCodeLine ("tax");
break;
case 3:
AddCodeLine ("lda sreg+1");
AddCodeLine ("ora #$%02X", Mask);
AddCodeLine ("sta sreg+1");
break;
default:
FAIL ("Invalid Byte for sign bit");
}
} else {
/* Since we are going to get back .A later anyways, we may just do the op on the
** higher bytes with whatever content currently in it.
*/
unsigned long Mask = ~((2UL << SignBitPos) - 1UL);
g_or (FullWidthFlags | CF_CONST, Mask);
}
/* Get back .A. We need to duplicate the TYA, rather than move it before
** the branch to share with the other label, because TYA changes some condition codes.
*/
g_defcodelabel (ZeroExtendLabel);
AddCodeLine ("tya");
}
} else {
/* Unsigned bit-field, needs only zero-extension. */
if (ZeroExtendMask != 0) {

View File

@ -37,10 +37,10 @@
#define CODEGEN_H
#include <inttypes.h>
/* common */
#include "coll.h"
#include "inttypes.h"
/* cc65 */
#include "segments.h"
@ -217,7 +217,7 @@ void g_reglong (unsigned Flags);
unsigned g_typeadjust (unsigned lhs, unsigned rhs);
/* Adjust the integer operands before doing a binary operation. lhs is a flags
** value, that corresponds to the value on TOS, rhs corresponds to the value
** in (e)ax. The return value is the the flags value for the resulting type.
** in (e)ax. The return value is the flags value for the resulting type.
*/
unsigned g_typecast (unsigned lhs, unsigned rhs);
@ -271,7 +271,7 @@ void g_restore_regvars (int StackOffs, int RegOffs, unsigned Bytes);
void g_getimmed (unsigned Flags, unsigned long Val, long Offs);
void g_getimmed (unsigned Flags, uintptr_t Val, long Offs);
/* Load a constant into the primary register */
void g_getstatic (unsigned Flags, uintptr_t Label, long Offs);
@ -461,7 +461,7 @@ void g_ge (unsigned flags, unsigned long val);
void g_res (unsigned n);
/* Reserve static storage, n bytes */
void g_defdata (unsigned flags, unsigned long val, long offs);
void g_defdata (unsigned flags, uintptr_t val, long offs);
/* Define data with the size given in flags */
void g_defbytes (const void* bytes, unsigned count);
@ -486,11 +486,11 @@ void g_initstatic (unsigned InitLabel, unsigned VarLabel, unsigned Size);
/*****************************************************************************/
void g_testbitfield (unsigned Flags, unsigned BitOffs, unsigned BitWidth);
/* Test bit-field in ax. */
/* Test bit-field in primary. */
void g_extractbitfield (unsigned Flags, unsigned FullWidthFlags, int IsSigned,
unsigned BitOffs, unsigned BitWidth);
/* Extract bits from bit-field in ax. */
/* Extract bits from bit-field in primary. */
/*****************************************************************************/
/* Switch statement */

View File

@ -56,6 +56,7 @@
#include "funcdesc.h"
#include "function.h"
#include "global.h"
#include "initdata.h"
#include "input.h"
#include "litpool.h"
#include "macrotab.h"

View File

@ -309,10 +309,10 @@ unsigned OptCmp1 (CodeSeg* S)
/* Insert the ora instead */
X = NewCodeEntry (OP65_ORA, L[0]->AM, L[0]->Arg, 0, L[0]->LI);
CS_InsertEntry (S, X, I);
CS_InsertEntry (S, X, I+3);
/* Remove all other instructions */
CS_DelEntries (S, I+1, 3);
CS_DelEntries (S, I, 3);
/* Remember, we had changes */
++Changes;

View File

@ -551,6 +551,24 @@ unsigned long GetIntegerTypeMax (const Type* Type)
static unsigned GetBitFieldMinimalTypeSize (unsigned BitWidth)
/* Return the size of the smallest integer type that may have BitWidth bits */
{
/* Since all integer types supported in cc65 for bit-fields have sizes that
** are powers of 2, we can just use this bit-twiddling trick.
*/
unsigned V = (int)(BitWidth - 1U) / (int)CHAR_BITS;
V |= V >> 1;
V |= V >> 2;
V |= V >> 4;
V |= V >> 8;
V |= V >> 16;
/* Return the result size */
return V + 1U;
}
static unsigned TypeOfBySize (unsigned Size)
/* Get the code generator replacement type of the object by its size */
{
@ -591,8 +609,7 @@ const Type* GetUnderlyingType (const Type* Type)
** bit-field, instead of the type used in the declaration, the truly
** underlying of the bit-field.
*/
unsigned Size = (int)(Type->A.B.Width - 1) / (int)CHAR_BITS + 1;
switch (Size) {
switch (GetBitFieldMinimalTypeSize (Type->A.B.Width)) {
case SIZEOF_CHAR: Type = IsSignSigned (Type) ? type_schar : type_uchar; break;
case SIZEOF_INT: Type = IsSignSigned (Type) ? type_int : type_uint; break;
case SIZEOF_LONG: Type = IsSignSigned (Type) ? type_long : type_ulong; break;
@ -646,8 +663,7 @@ TypeCode GetUnderlyingTypeCode (const Type* Type)
** bit-field, instead of the type used in the declaration, the truly
** underlying of the bit-field.
*/
unsigned Size = (int)(Type->A.B.Width - 1) / (int)CHAR_BITS + 1;
switch (Size) {
switch (GetBitFieldMinimalTypeSize (Type->A.B.Width)) {
case SIZEOF_CHAR: Underlying = T_CHAR; break;
case SIZEOF_INT: Underlying = T_INT; break;
case SIZEOF_LONG: Underlying = T_LONG; break;
@ -663,6 +679,39 @@ TypeCode GetUnderlyingTypeCode (const Type* Type)
const Type* GetBitFieldChunkType (const Type* Type)
/* Get the type needed to operate on the byte chunk containing the bit-field */
{
unsigned ChunkSize;
if ((Type->A.B.Width - 1U) / CHAR_BITS ==
(Type->A.B.Offs + Type->A.B.Width - 1U) / CHAR_BITS) {
/* T bit-field fits within its underlying type */
return GetUnderlyingType (Type);
}
ChunkSize = GetBitFieldMinimalTypeSize (Type->A.B.Offs + Type->A.B.Width);
if (ChunkSize < SizeOf (Type + 1)) {
/* The end of the bit-field is offset by some bits so that it requires
** more bytes to be accessed as a whole than its underlying type does.
** Note: In cc65 the bit offset is always less than CHAR_BITS.
*/
switch (ChunkSize) {
case SIZEOF_CHAR: return IsSignSigned (Type) ? type_schar : type_uchar;
case SIZEOF_INT: return IsSignSigned (Type) ? type_int : type_uint;
case SIZEOF_LONG: return IsSignSigned (Type) ? type_long : type_ulong;
default: return IsSignSigned (Type) ? type_int : type_uint;
}
}
/* We can always use the declarartion integer type as the chunk type.
** Note: A bit-field will not occupy bits located in bytes more than that
** of its declaration type in cc65. So this is OK.
*/
return Type + 1;
}
unsigned SizeOf (const Type* T)
/* Compute size of object represented by type array. */
{
@ -967,9 +1016,18 @@ const Type* IntPromotion (const Type* T)
*/
if (IsTypeBitField (T)) {
/* The standard rule is OK for now as we don't support bit-fields with widths > 16.
/* As we now support long bit-fields, we need modified rules for them:
** - If an int can represent all values of the bit-field, the bit-field is converted
** to an int;
** - Otherwise, if an unsigned int can represent all values of the bit-field, the
** bit-field is converted to an unsigned int;
** - Otherwise, the bit-field will have its declared integer type.
** These rules are borrowed from C++ and seem to be consistent with GCC/Clang's.
*/
return T->A.B.Width >= INT_BITS && IsSignUnsigned (T) ? type_uint : type_int;
if (T->A.B.Width > INT_BITS) {
return IsSignUnsigned (T) ? type_ulong : type_long;
}
return T->A.B.Width == INT_BITS && IsSignUnsigned (T) ? type_uint : type_int;
} else if (IsTypeChar (T)) {
/* An integer can represent all values from either signed or unsigned char, so convert
** chars to int.
@ -1127,6 +1185,15 @@ Type* NewBitFieldType (const Type* T, unsigned BitOffs, unsigned BitWidth)
int IsTypeFragBitField (const Type* T)
/* Return true if this is a bit-field that shares byte space with other fields */
{
return IsTypeBitField (T) &&
(T->A.B.Offs != 0 || T->A.B.Width != CHAR_BITS * SizeOf (T));
}
int IsClassObject (const Type* T)
/* Return true if this is a fully described object type */
{

View File

@ -313,6 +313,9 @@ TypeCode GetUnderlyingTypeCode (const Type* Type);
** Return TCode if it is not scalar.
*/
const Type* GetBitFieldChunkType (const Type* Type);
/* Get the type needed to operate on the byte chunk containing the bit-field */
unsigned SizeOf (const Type* T);
/* Compute size of object represented by type array. */
@ -556,6 +559,9 @@ INLINE int IsTypeBitField (const Type* T)
# define IsTypeBitField(T) (IsTypeSignedBitField (T) || IsTypeUnsignedBitField (T))
#endif
int IsTypeFragBitField (const Type* T);
/* Return true if this is a bit-field that shares byte space with other fields */
#if defined(HAVE_INLINE)
INLINE int IsTypeStruct (const Type* T)
/* Return true if this is a struct type */

Some files were not shown because too many files have changed in this diff Show More