Updated linuxdoc sources from https://github.com/groessler/cc65/tree/gh-pages-sgml.
This commit is contained in:
600
doc/atari.sgml
600
doc/atari.sgml
@@ -26,6 +26,16 @@ 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 - $D7FFF. Since the
|
||||
<tt/atarixl/ runtime has some <ref name="limitations" id="limitations">, 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 <htmlurl url="funcref.html" name="function
|
||||
reference">. Even functions marked as "platform dependent" may be available on
|
||||
@@ -35,35 +45,54 @@ information.
|
||||
|
||||
<sect>Binary format<p>
|
||||
|
||||
The standard binary output format generated by the linker for the
|
||||
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 <2 byte start address> <2 bytes end address>
|
||||
[program bytes]). These values are calculated in the crt0.s
|
||||
file from the __STARTUP_LOAD__ and __ZPSAVE_LOAD__ values, so keep
|
||||
this in mind if you create a custom linker config file and start
|
||||
moving segments around (see section
|
||||
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 only 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">).
|
||||
You can override this behaviour by creating your own crt0.s file and
|
||||
linking it into your program. A run vector is added to the end of the
|
||||
file ($02E0 <run vector>) and is calculated using
|
||||
__STARTUP_LOAD__ in crt0.s.
|
||||
|
||||
|
||||
<sect>Memory layout<p>
|
||||
|
||||
The default linker script assumes that the BASIC ROM is disabled (or
|
||||
the BASIC cartridge unplugged). This gives a usable memory range from
|
||||
$2E00 - $BC1F. The library startup code examines the
|
||||
<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 present, by inspecting the value in
|
||||
the MEMTOP ($2E5) variable. Then the initial stack pointer,
|
||||
which indicates the upper bound of memory used, is adjusted. The
|
||||
default load address of $2E00 was chosen to accommodate having
|
||||
a DOS loaded and a driver that resides in low memory such as the 850
|
||||
R: handler. You can override this behaviour by creating a custom
|
||||
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>
|
||||
@@ -86,6 +115,135 @@ Special locations:
|
||||
|
||||
</descrip><p>
|
||||
|
||||
<sect1><tt/atarixl/ target<p>
|
||||
|
||||
The startup code rearranges the memory as follows:
|
||||
|
||||
<enum>
|
||||
<item>Sceen 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]. Note that the default load address for <tt/atarixl/ is
|
||||
different (and lower) that the default load address for <tt/atari/. This is no problem since
|
||||
on the <tt/atarixl/ target the first load chunk makes sure that the loaded prgram won't overwrite
|
||||
memory below MEMLO. See <ref name="atarixl load chunks" id="xlchunks">.
|
||||
|
||||
|
||||
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 RAM 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-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".
|
||||
|
||||
|
||||
<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">.
|
||||
|
||||
|
||||
<sect>Platform specific header files<p>
|
||||
@@ -157,48 +315,43 @@ The names in the parentheses denote the symbols to be used for static linking of
|
||||
|
||||
<sect1>Graphics drivers<p>
|
||||
|
||||
<descrip>
|
||||
<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>
|
||||
|
||||
<tag><tt/atari10.tgi (atari_10)/</tag>
|
||||
|
||||
<tag><tt/atr10p2.tgi (atari_10p2)/</tag>
|
||||
|
||||
<tag><tt/atari11.tgi (atari_11)/</tag>
|
||||
|
||||
<tag><tt/atari14.tgi (atari_14)/</tag>
|
||||
|
||||
<tag><tt/atari15.tgi (atari_15)/</tag>
|
||||
|
||||
<tag><tt/atr15p2.tgi (atari_15p2)/</tag>
|
||||
|
||||
<tag><tt/atari3.tgi (atari_3)/</tag>
|
||||
|
||||
<tag><tt/atari4.tgi (atari_4)/</tag>
|
||||
|
||||
<tag><tt/atari5.tgi (atari_5)/</tag>
|
||||
|
||||
<tag><tt/atari6.tgi (atari_6)/</tag>
|
||||
|
||||
<tag><tt/atari7.tgi (atari_7)/</tag>
|
||||
|
||||
<tag><tt/atari8.tgi (atari_8)/</tag>
|
||||
|
||||
<tag><tt/atr8p2.tgi (atari_8p2)/</tag>
|
||||
|
||||
<tag><tt/atari9.tgi (atari_9)/</tag>
|
||||
|
||||
<tag><tt/atr9p2.tgi (atari_9p2)/</tag>
|
||||
|
||||
</descrip><p>
|
||||
|
||||
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.
|
||||
This 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/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
|
||||
@@ -251,41 +404,74 @@ the Atari ROM code.
|
||||
|
||||
<sect1>Extended memory drivers<p>
|
||||
|
||||
<descrip>
|
||||
|
||||
<tag><tt/atr130xe.emd (atari_130xe)/</tag>
|
||||
|
||||
</descrip><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>
|
||||
|
||||
<descrip>
|
||||
Currently there are two joystick drivers available:
|
||||
|
||||
<tag><tt/ataristd.joy (atari_stdjoy)/</tag>
|
||||
Supports up to four standard joysticks connected to the joystick ports of
|
||||
the Atari.
|
||||
|
||||
<tag><tt/atarim8.joy (atari_multijoy)/</tag>
|
||||
Supports up to eight standard joysticks connected to a MultiJoy adapter.
|
||||
|
||||
</descrip><p>
|
||||
<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>
|
||||
<caption>
|
||||
</table>
|
||||
|
||||
|
||||
<sect1>Mouse drivers<p>
|
||||
|
||||
Currently no drivers available (in fact, the API for loadable mouse drivers
|
||||
does not exist). There is a static driver you can use.
|
||||
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>
|
||||
<caption>
|
||||
</table>
|
||||
|
||||
All mouse devices connect to joystick port #0.
|
||||
|
||||
|
||||
<sect1>RS232 device drivers<p>
|
||||
|
||||
Currently there are no RS232 loadable drivers available for the Atari
|
||||
platform. There is a static driver you can use.
|
||||
Currently there is one RS232 driver. It uses the R: device (therefore
|
||||
a R: driver needs to be installed) and 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/atarixl/<label id="limitations"<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>
|
||||
|
||||
@@ -303,6 +489,143 @@ 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.
|
||||
|
||||
|
||||
<sect>Technical details<label id="techdetail"><p>
|
||||
|
||||
<sect1><tt/atari/<p>
|
||||
|
||||
<sect2>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 RAM memory area of the linker config file.
|
||||
</enum>
|
||||
|
||||
|
||||
<sect1><tt/atarixl/<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>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>
|
||||
|
||||
|
||||
@@ -335,6 +658,9 @@ feature in the <htmlurl url="ca65.html" name="assembler manual">.
|
||||
|
||||
<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
|
||||
@@ -348,7 +674,7 @@ memory area (assuming a reserved area from $4000 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 scripts
|
||||
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>
|
||||
@@ -360,30 +686,34 @@ 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, INIT, CODE, RODATA, and DATA segments (the whole user
|
||||
program).
|
||||
of the STARTUP, LOWCODE, INIT, 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 segment, which is
|
||||
defined in crt0.s. This cannot be changed without modifying and
|
||||
recompiling the cc65 atari runtime lib. Therefore the original EXE
|
||||
header must be discarded. It will be replaced by a user created
|
||||
one. The discarding is done by assigning the EXEHDR segment to the
|
||||
BANK memory area. The BANK memory area is discarded in the new linker
|
||||
script (written to file "").
|
||||
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 EXE header 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 EXE header
|
||||
and the second load chunk header.
|
||||
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__ = $800; # 2K stack
|
||||
__RESERVED_MEMORY__: value = $0000, weak = yes;
|
||||
__STACKSIZE__: value = $800 type = weak; # 2K stack
|
||||
__RESERVED_MEMORY__: value = $0000, type = weak;
|
||||
}
|
||||
FEATURES {
|
||||
STARTADDRESS: default = $2E00;
|
||||
@@ -391,18 +721,22 @@ FEATURES {
|
||||
MEMORY {
|
||||
ZP: start = $82, size = $7E, type = rw, define = yes;
|
||||
|
||||
HEADER: start = $0000, size = $6, file = %O; # first load chunk
|
||||
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;
|
||||
|
||||
BANK: start = $4000, size = $4000, file = "";
|
||||
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 = BANK, type = ro;
|
||||
EXEHDR: load = HEADER, type = ro;
|
||||
|
||||
NEXEHDR: load = HEADER, type = ro; # first load chunk
|
||||
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;
|
||||
INIT: load = RAMLO, type = ro, optional = yes;
|
||||
@@ -412,7 +746,6 @@ SEGMENTS {
|
||||
RODATA: load = RAM, type = ro, define = yes;
|
||||
DATA: load = RAM, type = rw, define = yes;
|
||||
BSS: load = RAM, type = bss, define = yes;
|
||||
ZPSAVE: load = RAM, type = bss, define = yes;
|
||||
|
||||
ZEROPAGE: load = ZP, type = zp;
|
||||
AUTOSTRT: load = RAM, type = ro; # defines program entry point
|
||||
@@ -430,12 +763,13 @@ FEATURES {
|
||||
</verb></tscreen>
|
||||
<p>
|
||||
|
||||
A new memory area BANK was added which describes the reserved area.
|
||||
It gets loaded with the contents of the old EXEHDR segment. But the
|
||||
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 EXEHDR segment get discarded.
|
||||
the MAINHDR segment get discarded.
|
||||
<p>
|
||||
The newly added NEXEHDR segment defines the correct EXE header. It
|
||||
The newly added NEXEHDR segment defines the correct chunk header for the
|
||||
first intended load chunk. It
|
||||
puts the STARTUP, LOWCODE, INIT, and CODE segments, which are the
|
||||
segments containing only code, into load chunk #1 (RAMLO memory area).
|
||||
<p>
|
||||
@@ -451,7 +785,6 @@ file (split.s):
|
||||
.import __DATA_LOAD__, __RODATA_LOAD__, __STARTUP_LOAD__
|
||||
|
||||
.segment "NEXEHDR"
|
||||
.word $FFFF
|
||||
.word __STARTUP_LOAD__
|
||||
.word __CODE_LOAD__ + __CODE_SIZE__ - 1
|
||||
|
||||
@@ -473,8 +806,8 @@ CODE, BSS, ZPSAVE into high memory (split2.cfg):
|
||||
|
||||
<tscreen><verb>
|
||||
SYMBOLS {
|
||||
__STACKSIZE__ = $800; # 2K stack
|
||||
__RESERVED_MEMORY__: value = $0000, weak = yes;
|
||||
__STACKSIZE__: value = $800 type = weak; # 2K stack
|
||||
__RESERVED_MEMORY__: value = $0000, type = weak;
|
||||
}
|
||||
FEATURES {
|
||||
STARTADDRESS: default = $2E00;
|
||||
@@ -482,18 +815,22 @@ FEATURES {
|
||||
MEMORY {
|
||||
ZP: start = $82, size = $7E, type = rw, define = yes;
|
||||
|
||||
HEADER: start = $0000, size = $6, file = %O; # first load chunk
|
||||
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;
|
||||
|
||||
BANK: start = $4000, size = $4000, file = "";
|
||||
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 = BANK, type = ro; # discarded old EXE header
|
||||
EXEHDR: load = HEADER, type = ro; # discarded old EXE header
|
||||
|
||||
NEXEHDR: load = HEADER, type = ro; # first load chunk
|
||||
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;
|
||||
|
||||
@@ -501,7 +838,6 @@ SEGMENTS {
|
||||
STARTUP: load = RAM, type = ro, define = yes;
|
||||
INIT: load = RAM, type = ro, optional = yes;
|
||||
CODE: load = RAM, type = ro, define = yes;
|
||||
ZPSAVE: load = RAM, type = bss, define = yes;
|
||||
BSS: load = RAM, type = bss, define = yes;
|
||||
|
||||
ZEROPAGE: load = ZP, type = zp;
|
||||
@@ -521,17 +857,16 @@ FEATURES {
|
||||
|
||||
New contents for NEXEHDR and CHKHDR are needed (split2.s):
|
||||
<tscreen><verb>
|
||||
.import __STARTUP_LOAD__, __ZPSAVE_LOAD__, __DATA_SIZE__
|
||||
.import __STARTUP_LOAD__, __BSS_LOAD__, __DATA_SIZE__
|
||||
.import __DATA_LOAD__, __RODATA_LOAD__
|
||||
|
||||
.segment "NEXEHDR"
|
||||
.word $FFFF
|
||||
.word __RODATA_LOAD__
|
||||
.word __DATA_LOAD__ + __DATA_SIZE__ - 1
|
||||
|
||||
.segment "CHKHDR"
|
||||
.word __STARTUP_LOAD__
|
||||
.word __ZPSAVE_LOAD__ - 1
|
||||
.word __BSS_LOAD__ - 1
|
||||
</verb></tscreen>
|
||||
|
||||
Compile with
|
||||
@@ -542,7 +877,7 @@ cl65 -t atari -C split2.cfg -o prog.com prog.c split2.s
|
||||
<sect2>Final note<label id="memhole_final_note"><p>
|
||||
|
||||
There are two other memory areas which don't appear directly in the
|
||||
linker script. They are the stack and the heap.
|
||||
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
|
||||
@@ -556,14 +891,47 @@ common/_heap.s defines the location of the heap and atari/crt0.s
|
||||
defines the location of the stack by initializing sp.
|
||||
|
||||
|
||||
<sect>Bugs/Feedback<p>
|
||||
<sect1>Upgrading from an older cc65 version<p>
|
||||
|
||||
If you have problems using the library, if you find any bugs, or if you're
|
||||
doing something interesting with it, I would be glad to hear from you. Feel
|
||||
free to contact me by email (<htmlurl url="mailto:uz@cc65.org"
|
||||
name="uz@cc65.org"> or <htmlurl url="mailto:chris@groessler.org"
|
||||
name="chris@groessler.org"> ).
|
||||
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 addess of the program. For the "system
|
||||
check" load chunk this had to be split into two memory assigments. 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>
|
||||
|
||||
Reference in New Issue
Block a user