mirror of
https://github.com/cc65/cc65.git
synced 2024-12-23 19:29:37 +00:00
d8c31cf1d3
The name RAM doesn't make much sense in general for a memeory area because i.e. the zero page is for sure RAM but is not part of the memory area named RAM. For disk based targets it makes sense to put the disk file more into focus and here MAIN means the main part of the file - in contrast to some header. Only for ROM based targets the name RAM is kept as it makes sense to focus on the difference between RAM and ROM.
1016 lines
40 KiB
Plaintext
1016 lines
40 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">
|
|
<date>2014-04-24
|
|
|
|
<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="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 <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>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].
|
|
|
|
Please note that the first load chunk (which checks the system
|
|
compatibilty 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-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 to run
|
|
on an Atari is provided in the <tt/targetutil/ directory (<tt/w2cas.com/).
|
|
|
|
<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>
|
|
|
|
Programs containing Atari specific code may use the <tt/atari.h/
|
|
header file.
|
|
|
|
|
|
<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>_rest_vecs
|
|
<item>_save_vecs
|
|
<item>_scroll
|
|
<item>_setcolor
|
|
<item>_setcolor_low
|
|
</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>
|
|
|
|
|
|
|
|
<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 uses the R: device (therefore
|
|
an 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/<#if output="info|latex2e"> limitations</#if><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>
|
|
|
|
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.
|
|
|
|
|
|
<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 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>
|
|
|
|
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>
|