mirror of
https://github.com/cc65/cc65.git
synced 2024-12-22 12:30:41 +00:00
1204 lines
47 KiB
Plaintext
1204 lines
47 KiB
Plaintext
<!doctype linuxdoc system>
|
|
|
|
<article>
|
|
<title>Atari specific information for cc65
|
|
<author>
|
|
<url url="mailto:shawnjefferson@24fightingchickens.com" name="Shawn Jefferson"> and<newline>
|
|
<url url="mailto:chris@groessler.org" name="Christian Groessler">
|
|
|
|
<abstract>
|
|
An overview over the Atari 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 runtime system as it comes
|
|
with the cc65 C compiler. It describes the memory layout, Atari specific
|
|
header files, available drivers, and any pitfalls specific to that
|
|
platform.
|
|
|
|
The Atari runtime support comes in two flavors: <tt/atari/ and <tt/atarixl/.
|
|
The <tt/atari/ target supports all Atari 8-bit computers, the <tt/atarixl/ only
|
|
supports XL type or newer machines (excluding the 600XL).
|
|
|
|
The <tt/atarixl/ runtime makes the whole 64K of memory available, with the
|
|
exception of the I/O area at $D000 - $D7FF. Since the
|
|
<tt/atarixl/ runtime has some <ref name="limitations" id="xllimitations">, it is
|
|
recommended to use the <tt/atari/ target unless lack of memory dictates the
|
|
use of the <tt/atarixl/ target.
|
|
|
|
Please note that Atari 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.
|
|
|
|
|
|
<sect>Binary format<p>
|
|
|
|
The Atari DOS executable file format supports more than one load block (<it/chunk/).
|
|
|
|
The default binary output format generated by the linker for the
|
|
Atari target is a machine language program with a standard executable
|
|
header (FF FF <load chunk #1> ... <load chunk #n>).
|
|
A load chunk has the format [<2 byte start address> <2 bytes end address>
|
|
<chunk data>].
|
|
A run vector is added to the end of the
|
|
file ($02E0 $02E1 <run vector>) and is calculated using
|
|
the <tt/start/ label in crt0.s. (Technically the run vector is also a load chunk,
|
|
but is not regarded as such here.)
|
|
|
|
An <tt/atari/ program has two load chunks, an <tt/atarixl/ program has three load
|
|
chunks. The load chunks are defined in the linker configuration files. For more
|
|
detailed information about the load chunks see the chapter
|
|
<ref name="Technical details" id="techdetail">. For the discussion here it's
|
|
sufficient to know that the first load chunk(s) do preparation work and the
|
|
main part of the program is in the last load chunk.
|
|
|
|
The values determining the size of the main part of the program (the second load
|
|
chunk for <tt/atari/, the third load chunk for <tt/atarixl/) are calculated in
|
|
the crt0.s file from the __STARTUP_LOAD__ and __BSS_LOAD__ values.
|
|
Be aware of that if you create a custom linker config file and start moving segments around (see section
|
|
<ref name="Reserving a memory area inside the program" id="memhole">).
|
|
|
|
|
|
<sect>Memory layout<p>
|
|
|
|
<sect1><tt/atari/ target<p>
|
|
|
|
The default linker config file assumes that the BASIC ROM is disabled (or
|
|
the BASIC cartridge unplugged). This gives a usable memory range of
|
|
[$2000-$BC1F]. The library startup code examines the
|
|
current memory configuration, which depends on the size of the
|
|
installed memory and cartridges. It does so by using the value in
|
|
the MEMTOP ($2E5) variable as highest memory address the program
|
|
can use. The initial stack pointer, which is the upper bound of
|
|
memory used by the program, is set to this value, minus an optionally
|
|
defined __RESERVED_MEMORY__ value.
|
|
|
|
The default load address of $2000 can be changed by creating a custom
|
|
linker config file or by using the "--start-addr" cl65 command line
|
|
argument or the "--start-addr" or "-S" ld65 command line arguments.
|
|
|
|
Please note that the first load chunk (which checks the available memory)
|
|
will always be loaded at $2E00, regardless of the specified start
|
|
address. This address can only be changed by a custom linker config file.
|
|
|
|
Special locations:
|
|
|
|
<descrip>
|
|
<tag/Text screen/
|
|
The text screen depends on the installed memory size and cartridges
|
|
and can be obtained from the SAVMSC variable ($58).
|
|
|
|
<tag/Stack/
|
|
The C runtime stack is located at MEMTOP and grows downwards,
|
|
regardless of how your linker config file is setup. This
|
|
accommodates the different memory configurations of the Atari
|
|
machines, as well as having a cartridge installed. You can override
|
|
this behaviour by writing your own crt0.s file and linking it to
|
|
your program (see also <ref name="Final note"
|
|
id="memhole_final_note">).
|
|
|
|
<tag/Heap/
|
|
The C heap is located at the end of the program and grows towards the C
|
|
runtime stack.
|
|
|
|
</descrip><p>
|
|
|
|
<sect1><tt/atarixl/ target<p>
|
|
|
|
The startup code rearranges the memory as follows:
|
|
|
|
<enum>
|
|
<item>Screen memory and display list are moved below the program start address.
|
|
<item>The ROM is disabled, making the memory in the areas [$C000-$CFFF]
|
|
and [$D800-$FFF9] available.
|
|
<item>Character generator data is copied from ROM to the CHARGEN location specified in the
|
|
linker config file. This is (in the default <tt/atarixl.cfg/ file) at the same address as
|
|
where it is in ROM ($E000, it can be changed, see <ref name="atarixl chargen location"
|
|
id="chargenloc">). With the character generator at $E000, there are two upper memory
|
|
areas available, [$D800-$DFFF] and [$E400-$FFF9].
|
|
</enum>
|
|
|
|
With the default load address of $2400 this gives a usable memory range of
|
|
[$2400-$CFFF].
|
|
|
|
Please note that the first load chunk (which checks the system
|
|
compatibility and available memory) will always be loaded at
|
|
$2E00, regardless of the specified start address. This address
|
|
can only be changed by a custom linker config file.
|
|
|
|
Special locations:
|
|
|
|
<descrip>
|
|
<tag/Text screen/
|
|
The text screen depends on the selected load address ($2400
|
|
by default), and resides directly before that address, rounded to the next
|
|
lower page boundary.
|
|
The screen memory's start address can be obtained from the SAVMSC variable
|
|
($58).
|
|
|
|
<tag/Stack/
|
|
The C runtime stack is located at end of the MAIN memory area ($CFFF)
|
|
and grows downwards.
|
|
|
|
<tag/Heap/
|
|
The C heap is located at the end of the program (end of BSS segment) and
|
|
grows towards the C runtime stack.
|
|
|
|
</descrip><p>
|
|
|
|
<sect>Linker configurations<p>
|
|
|
|
The ld65 linker comes with default config files for the Atari. There
|
|
are two targets for the Atari, <tt/atari/ and <tt/atarixl/.
|
|
The default config file for <tt/atari/ is selected with
|
|
<tt/-t atari/, and the default config file for <tt/atarixl/ is selected with
|
|
<tt/-t atarixl/.
|
|
The Atari package comes with additional secondary linker config files which
|
|
can be used via <tt/-t atari -C <configfile>/ (for <tt/atari/ target) or
|
|
<tt/-t atarixl -C <configfile>/ (for <tt/atarixl/ target).
|
|
|
|
<sect1><tt/atari/ config files<p>
|
|
|
|
<sect2>default config file (<tt/atari.cfg/)<p>
|
|
|
|
The default configuration is tailored to C programs. It creates files
|
|
which have a default load address of $2000.
|
|
|
|
The files generated by this config file include the
|
|
<ref name="&dquot;system check&dquot;" id="syschk"> load chunk. It can
|
|
optionally be left out, see <ref name="Getting rid of the &dquot;system check&dquot; load chunk" id="nosyschk">.
|
|
|
|
<sect2><tt/atari-asm.cfg/<p>
|
|
|
|
This config file aims to give the assembler programmer maximum
|
|
flexibility. All program segments (<tt/CODE/, <tt/DATA/, etc.) are
|
|
optional.
|
|
|
|
By default it creates regular DOS executable files, which have a default
|
|
load address of $2E00. It's also possible to generate an image of
|
|
just the program data without EXE header, load address, or (auto-)start address.
|
|
To you so, you have to define the symbols <tt/__AUTOSTART__/ and <tt/__EXEHDR__/
|
|
when linking the program. Therefore, to generate a "plain" binary file, pass the
|
|
options "<tt/-D__AUTOSTART__=1 -D__EXEHDR__=1/" to the linker.
|
|
It's also possible to create a non auto-starting program file, by defining
|
|
only the <tt/__AUTOSTART__/ symbol. Such a program has to be run manually
|
|
after being loaded by DOS (for example by using the "M" option of DOS 2.5).
|
|
Defining only the <tt/__EXEHDR__/ symbol will create a (useless) file which
|
|
doesn't conform to the DOS executable file format (like a "plain" binary file)
|
|
but still has the "autostart" load chunk appended.
|
|
|
|
The sections of the file which the defines refer to (<tt/__AUTOSTART__/ for
|
|
the autostart trailer, <tt/__EXEHDR__/ for the EXE header and load address)
|
|
is <it/left out/, keep this in mind.
|
|
|
|
The values you assign to the two symbols <tt/__AUTOSTART__/ and <tt/__EXEHDR__/
|
|
don't matter.
|
|
|
|
<sect2><tt/atari-asm-xex.cfg/<p>
|
|
|
|
This config file allows writing multi segment binaries easily, without having to
|
|
write the header explicitly on each segment.
|
|
|
|
It is similar to the <tt/atari-asm.cfg/ above, but uses the ATARI (xex) file
|
|
format support on LD65 instead of the standard binary output, so it does not
|
|
have the <tt/__AUTOSTART/ nor the <tt/__EXEHDR__/ symbols.
|
|
|
|
Note that each <tt/MEMORY/ area in the configuration file will have it's own
|
|
segment in the output file with the correct headers, and you can specify and
|
|
init address INITAD) for each memory area.
|
|
|
|
<sect2><tt/atari-cart.cfg/<p>
|
|
|
|
This config file can be used to create 8K or 16K cartridges. It's suited both
|
|
for C and assembly language programs.
|
|
|
|
By default, an 8K cartridge is generated. To create a 16K cartridge, pass the
|
|
size of the cartridge to the linker, like "<tt/-D__CARTSIZE__=0x4000/".
|
|
The only valid values for <tt/__CARTSIZE__/ are 0x2000 and 0x4000.
|
|
|
|
The option byte of the cartridge can be set with the <tt/__CARTFLAGS__/
|
|
value, passed to the linker. The default value is $01, which means
|
|
that the cartridge doesn't prevent the booting of DOS.
|
|
|
|
The option byte will be located at address $BFFD. For more information
|
|
about its use, see e.g. "Mapping the Atari".
|
|
|
|
<sect2><tt/atari-cassette.cfg/<p>
|
|
|
|
This config file can be used to create cassette boot files. It's suited both
|
|
for C and assembly language programs.
|
|
|
|
The size of a cassette boot file is restricted to 32K. Larger programs
|
|
would need to be split in more parts and the parts to be loaded manually.
|
|
|
|
To write the generated file to a cassette, a utility (<tt/w2cas.com/) to run
|
|
on an Atari is provided in the <tt/util/ directory of <tt/atari/ target dir.
|
|
|
|
<sect2><tt/atari-xex.cfg/<p>
|
|
|
|
This config file shows how to write a binary using the ATARI (xex) file format
|
|
support on LD65, this simplifies the memory areas and allows to add new memory
|
|
areas easily without writing new headers and trailers.
|
|
|
|
Note that the default C library includes the system-check chunk, so in this
|
|
linker configuration we suppress the importing of the header and trailer for
|
|
this chunk by defining the standard import symbols to a 0 value. For the
|
|
initialization address of the system-check chunk, the INITAD is set directly in
|
|
the configuration.
|
|
|
|
<sect1><tt/atarixl/ config files<p>
|
|
|
|
<sect2>default config file (<tt/atarixl.cfg/)<p>
|
|
|
|
The default configuration is tailored to C programs. It creates files
|
|
which have a default load address of $2400.
|
|
|
|
The files generated by this config file include the
|
|
<ref name="&dquot;system check&dquot;" id="syschkxl"> load chunk. It can
|
|
optionally be left out, see <ref name="Getting rid of the &dquot;system check&dquot; load chunk" id="nosyschk">.
|
|
|
|
<sect2><tt/atarixl-largehimem.cfg/<p>
|
|
|
|
This is the same as the default config file, but it rearranges the
|
|
high memory beneath the ROM into one large block. In order for this
|
|
config file to work, the runtime library has to be recompiled with a
|
|
special define. See the file <tt/libsrc/atari/Makefile.inc/ in the
|
|
source distribution.
|
|
|
|
The files generated by this config file include the
|
|
<ref name="&dquot;system check&dquot;" id="syschkxl"> load chunk. It can
|
|
optionally be left out, see <ref name="Getting rid of the &dquot;system check&dquot; load chunk" id="nosyschk">.
|
|
|
|
<sect2><tt/atarixl-xex.cfg/<p>
|
|
|
|
Similar to the <tt/atari-xex.cfg/ above, this config file shows how to write a
|
|
binary using the ATARI (xex) file format support on LD65.
|
|
|
|
In addition to the suppressing of the system-check headers and trailers, this
|
|
also suppresses the shadow-ram-preparation headers and trailers, but does this
|
|
by defining an "UNUSED" memory area that is not written to the output file.
|
|
|
|
|
|
<sect>Platform specific header files<p>
|
|
|
|
Programs containing Atari specific code may use the <tt/atari.h/
|
|
header file.
|
|
|
|
This also includes access to operating system locations (e.g. hardware shadow registers) by a structure called
|
|
"<tt/OS/".
|
|
The names are the usual ones you can find in system reference manuals. Example:
|
|
|
|
<tscreen><verb>
|
|
...
|
|
OS.savmsc = ScreenMemory;
|
|
OS.color4 = 14; // white frame
|
|
if (OS.stick0 != 15 || OS.ch != 255) // key or stick input?
|
|
...
|
|
</verb></tscreen>
|
|
|
|
Please note that memory location 762/$2FA is called "<tt/char_/" while the original name "<tt/char/" conflicts with the C keyword.
|
|
|
|
If you like to use the OS names and locations for the original Atari 800 operating system, please "<tt/#define OSA/" before including the
|
|
<tt/atari.h/ header file.
|
|
If you like to target the floating point register model of revision 2 machines, put a "<tt/#define OS_REV2/" before including <tt/atari.h/.
|
|
|
|
Access to the Basic programming language zero page variables is established by the structure "<tt/BASIC/".
|
|
|
|
<sect1>Atari specific functions<p>
|
|
|
|
The functions and global variable listed below are special for the Atari.
|
|
See the <url url="funcref.html" name="function reference"> for declaration and usage.
|
|
|
|
<itemize>
|
|
<item>get_ostype
|
|
<item>get_tv
|
|
<item>_dos_type
|
|
<item>_gtia_mkcolor
|
|
<item>_getcolor
|
|
<item>_getdefdev
|
|
<item>_graphics
|
|
<item>_is_cmdline_dos
|
|
<item>_rest_vecs
|
|
<item>_save_vecs
|
|
<item>_scroll
|
|
<item>_setcolor
|
|
<item>_setcolor_low
|
|
<item>waitvsync
|
|
</itemize>
|
|
|
|
|
|
<sect1>Hardware access<p>
|
|
|
|
The following pseudo variables declared in the <tt/atari.h/ header
|
|
file do allow access to hardware located in the address space. Some
|
|
variables are structures, accessing the struct fields will access the
|
|
chip registers.
|
|
|
|
<descrip>
|
|
|
|
<tag><tt/GTIA_READ/ and <tt/GTIA_WRITE/</tag>
|
|
The <tt/GTIA_READ/ structure allows read access to the GTIA. The
|
|
<tt/GTIA_WRITE/ structure allows write access to the GTIA.
|
|
See the <tt/_gtia.h/ header file located in the include directory
|
|
for the declaration of the structure.
|
|
|
|
<tag><tt/POKEY_READ/ and <tt/POKEY_WRITE/</tag>
|
|
The <tt/POKEY_READ/ structure allows read access to the POKEY. The
|
|
<tt/POKEY_WRITE/ structure allows write access to the POKEY.
|
|
See the <tt/_pokey.h/ header file located in the include directory
|
|
for the declaration of the structure.
|
|
|
|
<tag><tt/ANTIC/</tag>
|
|
The <tt/ANTIC/ structure allows read access to the ANTIC.
|
|
See the <tt/_antic.h/ header file located in the include directory
|
|
for the declaration of the structure.
|
|
|
|
<tag><tt/PIA/</tag>
|
|
The <tt/PIA/ structure allows read access to the PIA 6520.
|
|
See the <tt/_pia.h/ header file located in the include directory
|
|
for the declaration of the structure.
|
|
|
|
</descrip><p>
|
|
|
|
<sect1>Display lists<p>
|
|
|
|
A major feature of the Atari graphics chip "ANTIC" is to
|
|
process instructions for the display generation.
|
|
cc65 supports constructing these display lists by offering defines
|
|
for the instructions. In conjunction with the "void"-variable extension
|
|
of cc65, display lists can be created quite comfortable:
|
|
|
|
<tscreen><verb>
|
|
...
|
|
unsigned char ScreenMemory[100];
|
|
|
|
void DisplayList =
|
|
{
|
|
DL_BLK8,
|
|
DL_BLK8,
|
|
DL_BLK8,
|
|
DL_LMS(DL_CHR20x8x2),
|
|
ScreenMemory,
|
|
DL_CHR20x8x2,
|
|
DL_CHR20x8x2,
|
|
DL_CHR20x8x2,
|
|
DL_BLK4,
|
|
DL_CHR20x8x2,
|
|
DL_JVB,
|
|
&DisplayList
|
|
};
|
|
...
|
|
OS.sdlst = &DisplayList;
|
|
...
|
|
</verb></tscreen>
|
|
|
|
Please inspect the <tt/_antic.h/ header file to determine the supported
|
|
instruction names. Modifiers on instructions can be nested without need
|
|
for an order:
|
|
|
|
<tt/DL_LMS(DL_HSCROL(DL_VSCROL(DL_DLI(DL_MAP80x4x2))))/
|
|
|
|
Please mind that ANTIC has memory alignment requirements for "player
|
|
missile graphics"-data, font data, display lists and screen memory. Creation
|
|
of a special linker configuration with appropriate aligned segments and
|
|
switching to that segment in the c-code is usually necessary. A more memory
|
|
hungry solution consists in using the "<tt/posix_memalign()/" function in
|
|
conjunction with copying your data to the allocated memory.
|
|
|
|
<sect1>Character mapping<p>
|
|
|
|
The Atari has two representations for characters:
|
|
<enum>
|
|
<item> ATASCII is character mapping which is similar to ASCII and used
|
|
by the CIO system of the OS. This is the default mapping of cc65 when
|
|
producing code for the atari target.
|
|
<item> The internal/screen mapping represents the real value of the
|
|
screen ram when showing a character.
|
|
</enum>
|
|
|
|
For direct memory access (simplicity and speed) enabling the internal
|
|
mapping can be useful. This can be achieved by including the
|
|
"<tt/atari_screen_charmap.h/" header.
|
|
|
|
A word of caution: Since the <tt/0x00/ character has to be mapped in an
|
|
incompatible way to the C-standard, the usage of string functions in
|
|
conjunction with internal character mapped strings delivers unexpected
|
|
results regarding the string length. The end of strings are detected where
|
|
you may not expect them (too early or (much) too late). Internal mapped
|
|
strings typically support the "<tt/mem...()/" functions.
|
|
|
|
<em>For assembler sources the macro "<tt/scrcode/" from the "<tt/atari.mac/"
|
|
package delivers the same feature.</em>
|
|
|
|
You can switch back to the ATASCII mapping by including
|
|
"<tt/atari_atascii_charmap.h/".
|
|
|
|
A final note: Since cc65 has currently some difficulties with string merging
|
|
under different mappings, defining remapped strings works only flawlessly
|
|
with static array initialization:
|
|
|
|
<tscreen><verb>
|
|
#include <atari_screen_charmap.h>
|
|
char pcScreenMappingString[] = "Hello Atari!";
|
|
|
|
#include <atari_atascii_charmap.h>
|
|
char pcAtasciiMappingString[] = "Hello Atari!";
|
|
</verb></tscreen>
|
|
|
|
delivers correct results, while
|
|
|
|
<tscreen><verb>
|
|
#include <atari_screen_charmap.h>
|
|
char* pcScreenMappingString = "Hello Atari!";
|
|
|
|
#include <atari_atascii_charmap.h>
|
|
char* pcAtasciiMappingString = "Hello Atari!";
|
|
</verb></tscreen>
|
|
|
|
does not.
|
|
|
|
<sect1>Keyboard codes<p>
|
|
|
|
For direct keyboard scanning in conjunction with e.g. the OS location "CH" (764/$2FC),
|
|
all keyboard codes are available as defined values on C and assembler side.
|
|
|
|
Example:
|
|
<tscreen><verb>
|
|
...
|
|
while (!kbhit());
|
|
switch (OS.ch)
|
|
{
|
|
case KEY_RETURN:
|
|
...
|
|
case KEY_SPACE:
|
|
...
|
|
case KEY_1:
|
|
...
|
|
}
|
|
...
|
|
</verb></tscreen>
|
|
|
|
You can find the C defines in the file "<tt/atari.h/" or "<tt/atari.inc/" for the assembler variant.
|
|
|
|
|
|
<sect>Loadable drivers<p>
|
|
|
|
The names in the parentheses denote the symbols to be used for static linking of the drivers.
|
|
|
|
|
|
<sect1>Graphics drivers<p>
|
|
|
|
<table><tabular ca="rrrr">
|
|
<tt/atari/|<tt/atarixl/|screen resolution|display pages@<hline>
|
|
<tt/atr3.tgi (atr3_tgi)/|<tt/atrx3.tgi (atrx3_tgi)/|40x24x4 (CIO mode 3, ANTIC mode 8)|1@
|
|
<tt/atr4.tgi (atr4_tgi)/|<tt/atrx4.tgi (atrx4_tgi)/|80x48x2 (CIO mode 4, ANTIC mode 9)|1@
|
|
<tt/atr5.tgi (atr5_tgi)/|<tt/atrx5.tgi (atrx5_tgi)/|80x48x4 (CIO mode 5, ANTIC mode A)|1@
|
|
<tt/atr6.tgi (atr6_tgi)/|<tt/atrx6.tgi (atrx6_tgi)/|160x96x2 (CIO mode 6, ANTIC mode B)|1@
|
|
<tt/atr7.tgi (atr7_tgi)/|<tt/atrx7.tgi (atrx7_tgi)/|160x96x4 (CIO mode 7, ANTIC mode D)|1@
|
|
<tt/atr8.tgi (atr8_tgi)/|<tt/atrx8.tgi (atrx8_tgi)/|320x192x2 (CIO mode 8, ANTIC mode F)|1@
|
|
<tt/atr8p2.tgi (atr8p2_tgi)/|<tt/atrx8p2.tgi (atrx8p2_tgi)/|320x192x2 (CIO mode 8, ANTIC mode F)|2@
|
|
<tt/atr9.tgi (atr9_tgi)/|<tt/atrx9.tgi (atrx9_tgi)/|80x192x16b (CIO mode 9, ANTIC mode F, GTIA mode $40)|1@
|
|
<tt/atr9p2.tgi (atr9p2_tgi)/|<tt/atrx9p2.tgi (atrx9p2_tgi)/|80x192x16b (CIO mode 9, ANTIC mode F, GTIA mode $40)|2@
|
|
<tt/atr10.tgi (atr10_tgi)/|<tt/atrx10.tgi (atrx10_tgi)/|80x192x9 (CIO mode 10, ANTIC mode F, GTIA mode $80)|1@
|
|
<tt/atr10p2.tgi (atr10p2_tgi)/|<tt/atrx10p2.tgi (atrx10p2_tgi)/|80x192x9 (CIO mode 10, ANTIC mode F, GTIA mode $80)|2@
|
|
<tt/atr11.tgi (atr11_tgi)/|<tt/atrx11.tgi (atrx11_tgi)/|80x192x16h (CIO mode 11, ANTIC mode F, GTIA mode $C0)|1@
|
|
<tt/atr14.tgi (atr14_tgi)/|<tt/atrx14.tgi (atrx14_tgi)/|160x192x2 (CIO mode 14, ANTIC mode C)|1@
|
|
<tt/atr15.tgi (atr15_tgi)/|<tt/atrx15.tgi (atrx15_tgi)/|160x192x4 (CIO mode 15, ANTIC mode E)|1@
|
|
<tt/atr15p2.tgi (atr15p2_tgi)/|<tt/atrx15p2.tgi (atrx15p2_tgi)/|160x192x4 (CIO mode 15, ANTIC mode E)|2
|
|
</tabular>
|
|
<!-- <caption>bla bla -->
|
|
</table>
|
|
|
|
|
|
Many graphics modes require more memory than the text screen which is
|
|
in effect when the program starts up. Therefore the programmer has to
|
|
tell the program beforehand the memory requirements of the graphics
|
|
modes the program intends to use.
|
|
|
|
On the <tt/atari/ target his can be done by using the __RESERVED_MEMORY__
|
|
linker config variable. The number specified there describes the number
|
|
of bytes to subtract from the top of available memory as seen from the
|
|
runtime library. This memory is then used by the screen buffer.
|
|
|
|
On the <tt/atarixl/ target the screen memory resides below the program
|
|
load address. In order to reserve memory for a graphics mode, one
|
|
simply uses a higher program load address. There are restrictions on
|
|
selectable load addresses,
|
|
see <ref name="Selecting a good program load address" id="loadaddr">.
|
|
|
|
The numbers for the different graphics modes presented below should
|
|
only be seen as a rule of thumb. Since the screen buffer memory needs
|
|
to start at specific boundaries, the numbers depend on the current top
|
|
of available memory.
|
|
The following numbers were determined by a BASIC program.
|
|
|
|
<table>
|
|
<tabular ca="rr">
|
|
graphics mode|reserved memory@<hline>
|
|
0|1@
|
|
1|1@
|
|
2|1@
|
|
3|1@
|
|
4|1@
|
|
5|182@
|
|
6|1182@
|
|
7|3198@
|
|
8|7120@
|
|
9|7146@
|
|
10|7146@
|
|
11|7146@
|
|
12|162@
|
|
13|1@
|
|
14|3278@
|
|
15|7120@
|
|
16|1@
|
|
17|1@
|
|
18|1@
|
|
19|1@
|
|
20|1@
|
|
21|184@
|
|
22|1192@
|
|
23|3208@
|
|
24|7146@
|
|
25|7146@
|
|
26|7146@
|
|
27|7146@
|
|
28|162@
|
|
29|1@
|
|
30|3304@
|
|
31|7146
|
|
</tabular>
|
|
<caption>reserved memory required for different graphics modes
|
|
</table>
|
|
|
|
The values of "1" are needed because the graphics command crashes if
|
|
it doesn't have at least one byte available. This seems to be a bug of
|
|
the Atari ROM code.
|
|
|
|
Default drivers: <tt/atr8.tgi (atr8_tgi)/ and <tt/atrx8.tgi (atrx8_tgi)/.
|
|
|
|
<sect1>Extended memory drivers<p>
|
|
|
|
Currently there is only one extended memory driver. It manages the second 64K of a 130XE.
|
|
|
|
<table>
|
|
<tabular ca="rr">
|
|
<tt/atari/|<tt/atarixl/@<hline>
|
|
<tt/atr130.emd (atr130_emd)/|<tt/atrx130.emd (atrx130_emd)/
|
|
</tabular>
|
|
</table>
|
|
|
|
<sect1>Joystick drivers<p>
|
|
|
|
Currently there are two joystick drivers available:
|
|
|
|
<table>
|
|
<tabular ca="rrr">
|
|
<tt/atari/|<tt/atarixl/|description@<hline>
|
|
<tt/atrstd.joy (atrstd_joy)/|<tt/atrxstd.joy (atrxstd_joy)/|Supports up to two/four standard joysticks connected to the joystick ports of the Atari. (Four on the pre-XL systems, two on XL or newer.)@
|
|
<tt/atrmj8.joy (atrmj8_joy)/|<tt/atrxmj8.joy (atrxmj8_joy)/|Supports up to eight standard joysticks connected to a MultiJoy adapter.
|
|
</tabular>
|
|
</table>
|
|
|
|
Default drivers: <tt/atrstd.joy (atrstd_joy)/ and <tt/atrxstd.joy (atrxstd_joy)/.
|
|
|
|
<sect1>Mouse drivers<p>
|
|
|
|
Currently there are five mouse drivers available:
|
|
|
|
<table>
|
|
<tabular ca="rrr">
|
|
<tt/atari/|<tt/atarixl/|description@<hline>
|
|
<tt/atrjoy.mou (atrjoy_mou)/|<tt/atrxjoy.mou (atrxjoy_mou)/|Supports a mouse emulated by a standard joystick.@
|
|
<tt/atrst.mou (atrst_mou)/|<tt/atrxst.mou (atrxst_mou)/|Supports an Atari ST mouse.@
|
|
<tt/atrami.mou (atrami_mou)/|<tt/atrxami.mou (atrxami_mou)/|Supports an Amiga mouse.@
|
|
<tt/atrtrk.mou (atrtrk_mou)/|<tt/atrxtrk.mou (atrxtrk_mou)/|Supports an Atari trakball.@
|
|
<tt/atrtt.mou (atrtt_mou)/|<tt/atrxtt.mou (atrxtt_mou)/|Supports an Atari touch tablet.
|
|
</tabular>
|
|
</table>
|
|
|
|
All mouse devices connect to joystick port #0.
|
|
|
|
Default drivers: <tt/atrst.mou (atrst_mou)/ and <tt/atrxst.mou (atrxst_mou)/.
|
|
|
|
<sect2>Mouse callbacks<p>
|
|
|
|
There are two mouse callbacks available.
|
|
<p>
|
|
The "text mode" callbacks (<tt/mouse_txt_callbacks/) display the mouse cursor as a "diamond" character
|
|
on the standard "GRAPHICS 0" text mode screen. The mouse cursor character can be changed by an
|
|
assembly file defining the character by exporting the zeropage symbol <tt/mouse_txt_char/.
|
|
The default file looks like this:
|
|
<tscreen><verb>
|
|
.export mouse_txt_char : zp = 96 ; 'diamond' screen code
|
|
</verb></tscreen>
|
|
<p>
|
|
The "P/M" callbacks (<tt/mouse_pm_callbacks/) use Player-Missile graphics for the mouse cursor.
|
|
The cursor shape can be changed, too, by an assembly file. Here's the default shape definition:
|
|
<tscreen><verb>
|
|
.export mouse_pm_bits
|
|
.export mouse_pm_height : zeropage
|
|
.export mouse_pm_hotspot_x : zeropage
|
|
.export mouse_pm_hotspot_y : zeropage
|
|
.rodata
|
|
mouse_pm_bits:
|
|
.byte %11110000
|
|
.byte %11000000
|
|
.byte %10100000
|
|
.byte %10010000
|
|
.byte %10001000
|
|
.byte %00000100
|
|
.byte %00000010
|
|
mouse_pm_height = * - mouse_pm_bits
|
|
; hot spot is upper left corner
|
|
mouse_pm_hotspot_x = 0
|
|
mouse_pm_hotspot_y = 0
|
|
</verb></tscreen>
|
|
<p>
|
|
<tt/mouse_pm_bits/ defines the shape of the cursor, <tt/mouse_pm_height/ defines the number of
|
|
bytes in <tt/mouse_pm_bits/. <tt/mouse_pm_hotspot_x/ and <tt/mouse_pm_hotspot_y/ define the
|
|
position in the shape where "the mouse points to". When using this callback page #6 ($600
|
|
- $6FF) is used for the P/M graphics data and no P/M graphics can otherwise be used
|
|
by the program. The height of the shape (<tt/mouse_pm_height/)
|
|
must not exceed 32 lines since the callback routines cannot handle more than 32 lines.
|
|
<p>
|
|
The default callbacks definition (<tt/mouse_def_callbacks/) is an alias for the "P/M" callbacks.
|
|
|
|
<sect1>RS232 device drivers<p>
|
|
|
|
Currently there is one RS232 driver. It supports up to 9600 baud, requires hardware flow control
|
|
(RTS/CTS) and uses the R: device (therefore an R: driver needs to be installed). It was tested
|
|
with the 850 interface module.
|
|
|
|
<table>
|
|
<tabular ca="rr">
|
|
<tt/atari/|<tt/atarixl/@<hline>
|
|
<tt/atrrdev.ser (atrrdev_ser)/|<tt/atrxrdev.ser (atrxrdev_ser)/
|
|
</tabular>
|
|
</table>
|
|
|
|
|
|
<sect>Limitations<p>
|
|
|
|
<sect1><tt/Realtime clock/<label id="realtimeclock"<p>
|
|
|
|
Access to the realtime clock is supported only when running on SpartaDOS-X.
|
|
There needs to be a realtime clock driver installed. This is normally the case
|
|
in the default installation (CONFIG.SYS) of SpartaDOS-X.
|
|
A missing realtime clock driver in SpartaDOS-X is not supported, and the program
|
|
may crash when calling the <tt/clock_settime()/ or <tt/clock_gettime()/
|
|
functions.
|
|
|
|
The resolution of the realtime clock driver is 1 second.
|
|
|
|
<sect1><tt/atarixl target/<#if output="info|latex2e"> limitations</#if><label id="xllimitations"<p>
|
|
|
|
<itemize>
|
|
<item>The display is cleared at program start and at program termination. This is a side
|
|
effect of relocating the display memory below the program start address.
|
|
<item>Not all possible CIO and SIO functions are handled by the runtime stub code which banks
|
|
the ROM in and out. All functions used by the runtime library are handled, though.
|
|
<item>The <tt/_sys()/ function is not supported.
|
|
<item>It is not compatible with DOSes or other programs using the memory below the ROM.
|
|
</itemize>
|
|
|
|
<sect>DIO implementation<label id="dio"><p>
|
|
|
|
The Atari supports disk drives with either 128 or 256 byte sectors.
|
|
The first three sectors of any disk are always 128 bytes long though. This is
|
|
because the system can only boot from 128 bytes sectors.
|
|
|
|
Therefore the DIO read and write functions transfer only 128 bytes
|
|
for sectors 1 to 3, regardless of the type of diskette.
|
|
|
|
|
|
<sect>CONIO implementation<label id="conio"><p>
|
|
|
|
The console I/O is speed optimized therefore support for XEP80 hardware
|
|
or f80.com software is missing. Of course you may use stdio.h functions.
|
|
|
|
<tt/cprintf/ targets a 40 character line. On a 20-column display this has
|
|
the unexpected effect of a blank line after your text. On such displays you can either
|
|
use for example <tt/gotoxy(20,0)/ to target the "next" line, or you can switch to <tt/write()/
|
|
function which does not have this side effect.
|
|
|
|
|
|
<sect>Technical details<label id="techdetail"><p>
|
|
|
|
<sect1><tt/atari/<#if output="info|latex2e"> details</#if><p>
|
|
|
|
<sect2><#if output="info|latex2e"><tt/atari/ </#if>Load chunks<p>
|
|
|
|
An <tt/atari/ program contains two load chunks.
|
|
|
|
<enum>
|
|
<item>"system check"<label id="syschk">&nl;
|
|
This load chunk is always loaded at address $2E00, and checks if the system has
|
|
enough memory to run the program. It also checks if the program start address is not
|
|
below MEMLO. If any of the checks return false, the loading of the program is aborted.&nl;
|
|
The contents of this chunk come from the SYSCHKCHNK memory area of the linker config file.
|
|
<item>main program&nl;
|
|
This load chunk is loaded at the selected program start address (default $2000) and
|
|
contains all of the code and data of the program.&nl;
|
|
The contents of this chunk come from the MAIN memory area of the linker config file.
|
|
</enum>
|
|
|
|
|
|
<sect1><tt/atarixl/<#if output="info|latex2e"> details</#if><p>
|
|
|
|
<sect2>General operation<p>
|
|
|
|
The <tt/atarixl/ target banks out the ROM while the program is running in
|
|
order to make more memory available to the program.
|
|
|
|
The screen memory is by default located at the top of available memory,
|
|
$BFFF if BASIC is not enabled, $9FFF if BASIC is enabled.
|
|
Therefore, in order to create a largest possible continuous memory area,
|
|
the screen memory is moved below the program load address. This gives
|
|
a memory area from <program load addr> to $CFFF.
|
|
|
|
The startup code installs wrappers for interrupt handlers and ROM routines.
|
|
When an interrupt or call to a ROM routine happens, the wrappers enable the
|
|
ROM, call the handler or routine, and disable the ROM again.
|
|
|
|
The "wrapping" of the ROM routines is done by changing the ROM entry
|
|
point symbols in <tt/atari.inc/ to point to the wrapper functions.
|
|
|
|
For ROM functions which require input or output buffers, the wrappers
|
|
copy the data as required to buffers in low memory.
|
|
|
|
<sect2><#if output="info|latex2e"><tt/atarixl/ </#if>Load chunks<label id="xlchunks"><p>
|
|
|
|
An <tt/atarixl/ program contains three load chunks.
|
|
|
|
<enum>
|
|
<item>"system check"<label id="syschkxl">&nl;
|
|
This load chunk is always loaded at address $2E00, and checks if the system is
|
|
suitable for running the program. It also checks if there is enough room between MEMLO
|
|
and the program start address to move the text mode screen buffer there. If any of the
|
|
checks return false, the loading of the program is aborted.&nl;
|
|
The contents of this chunk come from the SYSCHKCHNK memory area of the linker config file.
|
|
<item>"shadow RAM prepare"&nl;
|
|
The second load chunk gets loaded to the selected program load address (default $2400).
|
|
It moves the screen memory below the program load address, copies the character generator
|
|
from ROM to its new place in RAM, and copies the parts of the program which reside in
|
|
high memory below the ROM to their place. The high memory parts are included in this load chunk.&nl;
|
|
At the beginning of this load chunk there is a .bss area, which is not part of the
|
|
EXE file. Therefore the on-disk start address of this load chunk will be higher than the
|
|
selected start address. This .bss area (segment LOWBSS) contains the buffers for the
|
|
double buffering of ROM input and output data. If you add contents to this segment be aware
|
|
that the contents won't be zero initialized by the startup code.&nl;
|
|
The contents of this chunk come from the SRPREPCHNK memory area of the linker config file.
|
|
<item>main program&nl;
|
|
This load chunk is loaded just above the LOWBSS segment, replacing the code of
|
|
the previous load chunk. It contains all remaining code and data sections of the program,
|
|
including the startup code.&nl;
|
|
The contents of this chunk come from the RAM memory area of the linker config file.
|
|
</enum>
|
|
|
|
<sect2>Moving screen memory below the program start address<p>
|
|
|
|
When setting a graphics mode, the ROM looks at the RAMTOP location. RAMTOP
|
|
describes the amount of installed memory in pages (RAMTOP is only one byte).
|
|
The screen memory and display list are placed immediately below RAMTOP.
|
|
|
|
Now in order to relocate the screen memory to lower memory, the startup code
|
|
puts a value into RAMTOP which causes the ROM routines to allocate the display
|
|
memory below the program start address and then it issues a ROM call to setup
|
|
the regular text mode.
|
|
|
|
<sect2>Selecting a good program load address<label id="loadaddr"><p>
|
|
|
|
Due to the movement of the screen memory below the program start, there are some
|
|
load addresses which are sub-optimal because they waste memory or prevent a
|
|
higher resolution graphics mode from being enabled.
|
|
|
|
There are restrictions at which addresses screen memory (display buffer and display
|
|
list) can be placed. The display buffer cannot cross a 4K boundary and a display
|
|
list cannot cross a 1K boundary.
|
|
|
|
The startup code takes this into account when moving the screen memory down.
|
|
If the program start address (aligned to the next lower page boundary) minus
|
|
the screen buffer size would result in a screen buffer which spans a 4K
|
|
boundary, the startup code lowers RAMTOP to this 4K boundary.&nl;
|
|
The size of the screen buffer in text mode is 960 ($3C0) bytes. So, for
|
|
example, a selected start address of $2300 would span the 4K boundary
|
|
at $2000. The startup code would adjust the RAMTOP value in such way that
|
|
the screen memory would be located just below this boundary (at $1C40).
|
|
This results in the area [$2000-$22FF] being wasted.
|
|
Additionally, the program might fail to load since the lowest address used
|
|
by the screen memory could be below MEMLO. (The lowest address used in this
|
|
example would be at $1C20, where the display list would allocated.)
|
|
|
|
These calculations are performed by the startup code (in the first two
|
|
load chunks), but the startup code only takes the default 40x24 text mode
|
|
into account. If the program later wants to load TGI drivers which set
|
|
a more memory consuming graphics mode, the user has to pick a higher
|
|
load address.
|
|
Using higher resolution modes there is a restriction in the ROM that it
|
|
doesn't expect RAMTOP to be at arbitrary values. The Atari memory modules
|
|
came only in 8K or 16K sizes, so the ROM expects RAMTOP to only have
|
|
values in 8K steps. Therefore, when using the highest resolution modes
|
|
the program start address must be at an 8K boundary.
|
|
|
|
|
|
<sect2>Character generator location<label id="chargenloc"><p>
|
|
|
|
The default <tt/atarixl/ linker config file (<tt/atarixl.cfg/) leaves the
|
|
character generator location at the same address where it is in ROM
|
|
($E000). This has the disadvatage to split the upper memory into
|
|
two parts ([$D800-$DFFF] and
|
|
[$E400-$FFF9]). For applications which
|
|
require a large continuous upper memory area, an alternative linker
|
|
config file (<tt/atarixl-largehimem.cfg/) is provided. It relocates the
|
|
character generator to $D800, providing a single big upper
|
|
memory area at [$DC00-$FFF9].
|
|
|
|
With the character generator at a different address than in ROM, the routines
|
|
which enable and disable the ROM also have to update the chargen pointer.
|
|
This code is not enabled by default. In order to enable it,
|
|
uncomment the line which sets CHARGEN_RELOC in <tt/libsrc/atari/Makefile.inc/
|
|
and recompile the <tt/atarixl/ runtime library.
|
|
|
|
<sect>Other hints<p>
|
|
|
|
|
|
<sect1>Function keys<p>
|
|
|
|
Function keys are mapped to Atari + number key.
|
|
|
|
|
|
<sect1>Passing arguments to the program<p>
|
|
|
|
Command line arguments can be passed to <tt/main()/ when the used DOS supports it.
|
|
|
|
<enum>
|
|
<item>Arguments are separated by spaces.
|
|
<item>Leading and trailing spaces around an argument are ignored.
|
|
<item>The first argument passed to <tt/main/ is the program name.
|
|
<item>A maximum number of 16 arguments (including the program name) are
|
|
supported.
|
|
</enum>
|
|
|
|
|
|
<sect1>Interrupts<p>
|
|
|
|
The runtime for the Atari uses routines marked as <tt/.INTERRUPTOR/ for
|
|
interrupt handlers. Such routines must be written as simple machine language
|
|
subroutines and will be called automatically by the VBI handler code
|
|
when they are linked into a program. See the discussion of the <tt/.CONDES/
|
|
feature in the <url url="ca65.html" name="assembler manual">.
|
|
|
|
Please note that on the Atari targets the <tt/.INTERRUPTOR/s are being
|
|
run in NMI context. The other targets run them in IRQ context.
|
|
|
|
<sect1>Reserving a memory area inside a program<label id="memhole"><p>
|
|
|
|
(This section is primarily applicable to the <tt/atari/ target, but the
|
|
principles apply to <tt/atatixl/ as well.)
|
|
|
|
The Atari 130XE maps its additional memory into CPU memory in 16K
|
|
chunks at address $4000 to $7FFF. One might want to
|
|
prevent this memory area from being used by cc65. Other reasons to
|
|
prevent the use of some memory area could be to reserve space for the
|
|
buffers for display lists and screen memory.
|
|
<p>
|
|
The Atari executable format allows holes inside a program, e.g. one
|
|
part loads into $2E00 to $3FFF, going below the reserved
|
|
memory area (assuming a reserved area from $4000 to
|
|
$7FFF), and another part loads into $8000 to
|
|
$BC1F.
|
|
<p>
|
|
Each load chunk of the executable starts with a 4 byte header which
|
|
defines its load address and size. In the following linker config files
|
|
these headers are named HEADER and SECHDR (for the MEMORY layout), and
|
|
accordingly NEXEHDR and CHKHDR (for the SEGMENTS layout).
|
|
<p>
|
|
<sect2>Low code and high data example<p>
|
|
Goal: Create an executable with 2 load chunks which doesn't use the
|
|
memory area from $4000 to $7FFF. The CODE segment of
|
|
the program should go below $4000 and the DATA and RODATA
|
|
segments should go above $7FFF.
|
|
<p>
|
|
The main problem is that the EXE header generated by the cc65 runtime
|
|
lib is wrong. It defines a single load chunk with the sizes/addresses
|
|
of the STARTUP, LOWCODE, ONCE, CODE, RODATA, and DATA segments, in
|
|
fact, the whole user program (we're disregarding the "system check"
|
|
load chunk here).
|
|
<p>
|
|
The contents of the EXE header come from the EXEHDR and MAINHDR segments.
|
|
The EXEHDR segment just contains the $FFFF value which is required
|
|
to be the first bytes of the EXE file.&nl;
|
|
The MAINHDR are defined in in crt0.s. This cannot be changed without
|
|
modifying and recompiling the cc65 atari runtime library. Therefore
|
|
the original contents of this segment must be discarded and be
|
|
replaced by a user created one. This discarding is done by assigning the
|
|
MAINHDR segment to the (new introduced) DISCARD memory area. The DISCARD memory area is
|
|
thrown away in the new linker config file (written to file "").
|
|
We add a new FSTHDR segment for the chunk header of the first chunk.
|
|
<p>
|
|
The user needs to create a customized linker config file which adds
|
|
new memory areas and segments to hold the new header data for the first load
|
|
chunk and the header data for the second load chunk. Also an assembly source file
|
|
needs to be created which defines the contents of the new header data
|
|
for the two load chunks.
|
|
<p>
|
|
<p>
|
|
This is an example of a modified cc65 Atari linker configuration file
|
|
(split.cfg):
|
|
<tscreen><verb>
|
|
SYMBOLS {
|
|
__STACKSIZE__: value = $800 type = weak; # 2K stack
|
|
__RESERVED_MEMORY__: value = $0000, type = weak;
|
|
}
|
|
FEATURES {
|
|
STARTADDRESS: default = $2E00;
|
|
}
|
|
MEMORY {
|
|
ZP: start = $82, size = $7E, type = rw, define = yes;
|
|
|
|
HEADER: start = $0000, size = $2, file = %O; # first load chunk
|
|
|
|
FSTHDR: start = $0000, size = $4, file = %O; # second load chunk
|
|
RAMLO: start = %S, size = $4000 - %S, file = %O;
|
|
|
|
DISCARD: start = $4000, size = $4000, file = "";
|
|
|
|
SECHDR: start = $0000, size = $4, file = %O; # second load chunk
|
|
RAM: start = $8000, size = $3C20, file = %O; # $3C20: matches upper bound $BC1F
|
|
}
|
|
SEGMENTS {
|
|
EXEHDR: load = HEADER, type = ro;
|
|
|
|
MAINHDR: load = DISCARD, type = ro;
|
|
|
|
NEXEHDR: load = FSTHDR, type = ro; # first load chunk
|
|
STARTUP: load = RAMLO, type = ro, define = yes;
|
|
LOWCODE: load = RAMLO, type = ro, define = yes, optional = yes;
|
|
ONCE: load = RAMLO, type = ro, optional = yes;
|
|
CODE: load = RAMLO, type = ro, define = yes;
|
|
|
|
CHKHDR: load = SECHDR, type = ro; # second load chunk
|
|
RODATA: load = RAM, type = ro, define = yes;
|
|
DATA: load = RAM, type = rw, define = yes;
|
|
BSS: load = RAM, type = bss, define = yes;
|
|
|
|
ZEROPAGE: load = ZP, type = zp;
|
|
AUTOSTRT: load = RAM, type = ro; # defines program entry point
|
|
}
|
|
FEATURES {
|
|
CONDES: segment = ONCE,
|
|
type = constructor,
|
|
label = __CONSTRUCTOR_TABLE__,
|
|
count = __CONSTRUCTOR_COUNT__;
|
|
CONDES: segment = RODATA,
|
|
type = destructor,
|
|
label = __DESTRUCTOR_TABLE__,
|
|
count = __DESTRUCTOR_COUNT__;
|
|
}
|
|
</verb></tscreen>
|
|
<p>
|
|
|
|
A new memory area DISCARD was added.
|
|
It gets loaded with the contents of the (now unused) MAINHDR segment. But the
|
|
memory area isn't written to the output file. This way the contents of
|
|
the MAINHDR segment get discarded.
|
|
<p>
|
|
The newly added NEXEHDR segment defines the correct chunk header for the
|
|
first intended load chunk. It
|
|
puts the STARTUP, LOWCODE, ONCE, and CODE segments, which are the
|
|
segments containing only code, into load chunk #1 (RAMLO memory area).
|
|
<p>
|
|
The header for the second load chunk comes from the new CHKHDR
|
|
segment. It puts the RODATA, DATA, BSS, and ZPSAVE segments into load
|
|
chunk #2 (RAM memory area).
|
|
<p>
|
|
<p>
|
|
The contents of the new NEXEHDR and CHKHDR segments come from this
|
|
file (split.s):
|
|
<tscreen><verb>
|
|
.import __CODE_LOAD__, __BSS_LOAD__, __CODE_SIZE__
|
|
.import __DATA_LOAD__, __RODATA_LOAD__, __STARTUP_LOAD__
|
|
|
|
.segment "NEXEHDR"
|
|
.word __STARTUP_LOAD__
|
|
.word __CODE_LOAD__ + __CODE_SIZE__ - 1
|
|
|
|
.segment "CHKHDR"
|
|
.word __RODATA_LOAD__
|
|
.word __BSS_LOAD__ - 1
|
|
</verb></tscreen>
|
|
<p>
|
|
Compile with
|
|
<tscreen><verb>
|
|
cl65 -t atari -C split.cfg -o prog.com prog.c split.s
|
|
</verb></tscreen>
|
|
|
|
<sect2>Low data and high code example<p>
|
|
|
|
|
|
Goal: Put RODATA and DATA into low memory and STARTUP, LOWCODE, ONCE,
|
|
CODE, BSS, ZPSAVE into high memory (split2.cfg):
|
|
|
|
<tscreen><verb>
|
|
SYMBOLS {
|
|
__STACKSIZE__: value = $800 type = weak; # 2K stack
|
|
__RESERVED_MEMORY__: value = $0000, type = weak;
|
|
}
|
|
FEATURES {
|
|
STARTADDRESS: default = $2E00;
|
|
}
|
|
MEMORY {
|
|
ZP: start = $82, size = $7E, type = rw, define = yes;
|
|
|
|
HEADER: start = $0000, size = $2, file = %O; # first load chunk
|
|
|
|
FSTHDR: start = $0000, size = $4, file = %O; # second load chunk
|
|
RAMLO: start = %S, size = $4000 - %S, file = %O;
|
|
|
|
DISCARD: start = $4000, size = $4000, file = "";
|
|
|
|
SECHDR: start = $0000, size = $4, file = %O; # second load chunk
|
|
RAM: start = $8000, size = $3C20, file = %O; # $3C20: matches upper bound $BC1F
|
|
}
|
|
SEGMENTS {
|
|
EXEHDR: load = HEADER, type = ro; # discarded old EXE header
|
|
|
|
MAINHDR: load = DISCARD, type = ro;
|
|
|
|
NEXEHDR: load = FSTHDR, type = ro; # first load chunk
|
|
RODATA: load = RAMLO, type = ro, define = yes;
|
|
DATA: load = RAMLO, type = rw, define = yes;
|
|
|
|
CHKHDR: load = SECHDR, type = ro; # second load chunk
|
|
STARTUP: load = RAM, type = ro, define = yes;
|
|
ONCE: load = RAM, type = ro, optional = yes;
|
|
CODE: load = RAM, type = ro, define = yes;
|
|
BSS: load = RAM, type = bss, define = yes;
|
|
|
|
ZEROPAGE: load = ZP, type = zp;
|
|
AUTOSTRT: load = RAM, type = ro; # defines program entry point
|
|
}
|
|
FEATURES {
|
|
CONDES: segment = ONCE,
|
|
type = constructor,
|
|
label = __CONSTRUCTOR_TABLE__,
|
|
count = __CONSTRUCTOR_COUNT__;
|
|
CONDES: segment = RODATA,
|
|
type = destructor,
|
|
label = __DESTRUCTOR_TABLE__,
|
|
count = __DESTRUCTOR_COUNT__;
|
|
}
|
|
</verb></tscreen>
|
|
|
|
New contents for NEXEHDR and CHKHDR are needed (split2.s):
|
|
<tscreen><verb>
|
|
.import __STARTUP_LOAD__, __BSS_LOAD__, __DATA_SIZE__
|
|
.import __DATA_LOAD__, __RODATA_LOAD__
|
|
|
|
.segment "NEXEHDR"
|
|
.word __RODATA_LOAD__
|
|
.word __DATA_LOAD__ + __DATA_SIZE__ - 1
|
|
|
|
.segment "CHKHDR"
|
|
.word __STARTUP_LOAD__
|
|
.word __BSS_LOAD__ - 1
|
|
</verb></tscreen>
|
|
|
|
Compile with
|
|
<tscreen><verb>
|
|
cl65 -t atari -C split2.cfg -o prog.com prog.c split2.s
|
|
</verb></tscreen>
|
|
|
|
<sect2>Final note<label id="memhole_final_note"><p>
|
|
|
|
There are two other memory areas which don't appear directly in the
|
|
linker config file. They are the stack and the heap.
|
|
|
|
The cc65 runtime lib places the stack location at the end of available
|
|
memory. This is dynamically set from the MEMTOP system variable at
|
|
startup. The heap is located in the area between the end of the BSS
|
|
segment and the top of the stack as defined by __STACKSIZE__.
|
|
|
|
If BSS and/or the stack shouldn't stay at the end of the program,
|
|
some parts of the cc65 runtime lib need to be replaced/modified.
|
|
|
|
common/_heap.s defines the location of the heap and atari/crt0.s
|
|
defines the location of the stack by initializing sp.
|
|
|
|
|
|
<sect1>Upgrading from an older cc65 version<p>
|
|
|
|
If you are using a customized linker config file you might get some errors
|
|
regarding the MAINHDR segment. Like this:
|
|
|
|
<tscreen><verb>
|
|
ld65: Error: Missing memory area assignment for segment 'MAINHDR'
|
|
</verb></tscreen>
|
|
|
|
The old "HEADER" memory description contained six bytes: $FFFF
|
|
and the first and last memory address of the program. For the "system
|
|
check" load chunk this had to be split into two memory assignments The
|
|
"HEADER" now only contains the $FFFF. The main program's first
|
|
and last memory address were moved to a new segment, called "MAINHDR",
|
|
which in the new linker config file goes into its own memory area (also
|
|
called "MAINHDR").&nl;&nl;
|
|
A simple way to adapt your old linker config file is to add the
|
|
following line to the "SEGMENTS" section:
|
|
|
|
<tscreen><verb>
|
|
MAINHDR: load = HEADER, type = ro;
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
<sect1>Getting rid of the "system check" load chunk<label id="nosyschk"><p>
|
|
|
|
If, for some reason, you don't want to include the "system check" load
|
|
chunk, you can do so by defining the symbol <tt/__SYSTEM_CHECK__/ when linking the
|
|
program. The "system check" chunk doesn't include vital parts of the
|
|
program. So if you don't want the system checks, it is save to leave them out.
|
|
This is probably mostly interesting for debugging.
|
|
|
|
When using cl65, you can leave it out with this command line:
|
|
|
|
<tscreen><verb>
|
|
cl65 -Wl -D__SYSTEM_CHECK__=1 <arguments>
|
|
</verb></tscreen>
|
|
|
|
The value you assign to <tt/__SYSTEM_CHECK__/ doesn't matter. If the
|
|
<tt/__SYSTEM_CHECK__/ symbol is defined, the load chunk won't be included.
|
|
|
|
|
|
<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>
|