add example of a memory configuration with holes; add cpg@aladdin.de
as bugs/feedback address git-svn-id: svn://svn.cc65.org/cc65/trunk@3179 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
225
doc/atari.sgml
225
doc/atari.sgml
@@ -5,7 +5,7 @@
|
|||||||
<title>Atari specific information for cc65
|
<title>Atari specific information for cc65
|
||||||
<author>Shawn Jefferson, <htmlurl url="mailto:shawnjefferson@24fightingchickens.com" name="shawnjefferson@24fightingchickens.com">
|
<author>Shawn Jefferson, <htmlurl url="mailto:shawnjefferson@24fightingchickens.com" name="shawnjefferson@24fightingchickens.com">
|
||||||
Christian Groessler, <htmlurl url="mailto:cpg@aladdin.de" name="cpg@aladdin.de">
|
Christian Groessler, <htmlurl url="mailto:cpg@aladdin.de" name="cpg@aladdin.de">
|
||||||
<date>16-Oct-2003
|
<date>14-Sep-2004
|
||||||
|
|
||||||
<abstract>
|
<abstract>
|
||||||
An overview over the Atari runtime system as it is implemented for the cc65 C
|
An overview over the Atari runtime system as it is implemented for the cc65 C
|
||||||
@@ -35,13 +35,15 @@ information.
|
|||||||
|
|
||||||
The standard binary output format generated by the linker for the
|
The standard binary output format generated by the linker for the
|
||||||
Atari target is a machine language program with a standard executable
|
Atari target is a machine language program with a standard executable
|
||||||
header (FF FF <start address> <end address>). These values are
|
header (FF FF <2 byte start address> <2 bytes end address>
|
||||||
calculated in the crt0.s file from the __CODE_LOAD__ and __BSS_LOAD__
|
[program bytes]). These values are calculated in the crt0.s
|
||||||
values, so keep this in mind if you create a custom linker config file
|
file from the __CODE_LOAD__ and __BSS_LOAD__ values, so keep this in
|
||||||
and start moving segments around. You can override this behaviour by
|
mind if you create a custom linker config file and start moving
|
||||||
creating your own crt0.s file and linking it into your program. A run
|
segments around (see section <ref name="Reserving a memory area inside the program" id="memhole">). You can
|
||||||
vector is added to the end of the file ($02E0 <run vector>)
|
override this behaviour by creating your own crt0.s file and linking
|
||||||
and is calculated using __CODE_LOAD__ in crt0.s also.
|
it into your program. A run vector is added to the end of the file
|
||||||
|
($02E0 <run vector>) and is calculated using
|
||||||
|
__CODE_LOAD__ in crt0.s.
|
||||||
|
|
||||||
|
|
||||||
<sect>Memory layout<p>
|
<sect>Memory layout<p>
|
||||||
@@ -71,7 +73,8 @@ Special locations:
|
|||||||
accomodates the different memory configurations of the Atari
|
accomodates the different memory configurations of the Atari
|
||||||
machines, as well as having a cartridge installed. You can override
|
machines, as well as having a cartridge installed. You can override
|
||||||
this behaviour by writing your own crt0.s file and linking it to
|
this behaviour by writing your own crt0.s file and linking it to
|
||||||
your program.
|
your program (see also <ref name="Final note"
|
||||||
|
id="memhole_final_note">).
|
||||||
|
|
||||||
<tag/Heap/
|
<tag/Heap/
|
||||||
The C heap is located at the end of the program and grows towards the C
|
The C heap is located at the end of the program and grows towards the C
|
||||||
@@ -187,6 +190,207 @@ platform. There is a static driver you can use.
|
|||||||
|
|
||||||
These are defined to be Atari + number key.
|
These are defined to be Atari + number key.
|
||||||
|
|
||||||
|
<sect1>Reserving a memory area inside the program<label id="memhole"><p>
|
||||||
|
|
||||||
|
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 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.
|
||||||
|
<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 runtine
|
||||||
|
lib is wrong. It defines a single load chunk with the sizes/addresses
|
||||||
|
of the CODE, RODATA, and DATA segments (the whole user program).
|
||||||
|
<p>
|
||||||
|
The contents of the EXE header come from the EXEHDR segment, which is
|
||||||
|
defined in crt0.s. This cannot be changed w/o modifiying and
|
||||||
|
recompiling the cc65 atari runtime lib. Therefore the original EXE
|
||||||
|
header must be discarded. It will be replaced by a user created
|
||||||
|
one.
|
||||||
|
<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 added
|
||||||
|
load chunk header data. Also an assembly source file needs to be
|
||||||
|
created which defines the contents of the new EXE header and the
|
||||||
|
second load chunk header.
|
||||||
|
<p>
|
||||||
|
<p>
|
||||||
|
This is a modified cc65 Atari linker configuration file (split.cfg):
|
||||||
|
<tscreen><verb>
|
||||||
|
MEMORY {
|
||||||
|
ZP: start = $82, size = $7E, type = rw, define = yes;
|
||||||
|
|
||||||
|
HEADER: start = $0000, size = $6, file = %O; # first load chunk
|
||||||
|
RAMLO: start = $2E00, size = $1200, file = %O;
|
||||||
|
|
||||||
|
BANK: 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 = wprot;
|
||||||
|
|
||||||
|
NEXEHDR: load = HEADER, type = wprot; # first load chunk
|
||||||
|
CODE: load = RAMLO, type = wprot, define = yes;
|
||||||
|
|
||||||
|
CHKHDR: load = SECHDR, type = wprot; # second load chunk
|
||||||
|
RODATA: load = RAM, type = wprot, 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 = wprot; # defines program entry point
|
||||||
|
}
|
||||||
|
FEATURES {
|
||||||
|
CONDES: segment = RODATA,
|
||||||
|
type = constructor,
|
||||||
|
label = __CONSTRUCTOR_TABLE__,
|
||||||
|
count = __CONSTRUCTOR_COUNT__;
|
||||||
|
CONDES: segment = RODATA,
|
||||||
|
type = destructor,
|
||||||
|
label = __DESTRUCTOR_TABLE__,
|
||||||
|
count = __DESTRUCTOR_COUNT__;
|
||||||
|
}
|
||||||
|
SYMBOLS {
|
||||||
|
__STACKSIZE__ = $800; # 2K stack
|
||||||
|
}
|
||||||
|
</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
|
||||||
|
memory area isn't written to the output file. This way the contents of
|
||||||
|
the EXEHDR segment get discarded.
|
||||||
|
<p>
|
||||||
|
The added NEXEHDR segment defines the correct EXE header. It puts only
|
||||||
|
the CODE segment 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 and DATA 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__
|
||||||
|
|
||||||
|
.segment "NEXEHDR"
|
||||||
|
.word $FFFF ; EXE file magic number
|
||||||
|
; 1st load chunk
|
||||||
|
.word __CODE_LOAD__
|
||||||
|
.word __CODE_LOAD__ + __CODE_SIZE__ - 1
|
||||||
|
|
||||||
|
.segment "CHKHDR"
|
||||||
|
; 2nd load chunk (contains with AUTOSTRT in fact a 3rd load chunk)
|
||||||
|
.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 CODE with BSS into high
|
||||||
|
memory (split2.cfg):
|
||||||
|
|
||||||
|
<tscreen><verb>
|
||||||
|
MEMORY {
|
||||||
|
ZP: start = $82, size = $7E, type = rw, define = yes;
|
||||||
|
|
||||||
|
HEADER: start = $0000, size = $6, file = %O; # first load chunk
|
||||||
|
RAMLO: start = $2E00, size = $1200, file = %O;
|
||||||
|
|
||||||
|
BANK: 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 = wprot; # discarded old EXE header
|
||||||
|
|
||||||
|
NEXEHDR: load = HEADER, type = wprot; # first load chunk
|
||||||
|
RODATA: load = RAMLO, type = wprot, define = yes;
|
||||||
|
DATA: load = RAMLO, type = rw, define = yes;
|
||||||
|
|
||||||
|
CHKHDR: load = SECHDR, type = wprot; # second load chunk
|
||||||
|
CODE: load = RAM, type = wprot, define = yes;
|
||||||
|
BSS: load = RAM, type = bss, define = yes;
|
||||||
|
|
||||||
|
ZEROPAGE: load = ZP, type = zp;
|
||||||
|
AUTOSTRT: load = RAM, type = wprot; # defines program entry point
|
||||||
|
}
|
||||||
|
FEATURES {
|
||||||
|
CONDES: segment = RODATA,
|
||||||
|
type = constructor,
|
||||||
|
label = __CONSTRUCTOR_TABLE__,
|
||||||
|
count = __CONSTRUCTOR_COUNT__;
|
||||||
|
CONDES: segment = RODATA,
|
||||||
|
type = destructor,
|
||||||
|
label = __DESTRUCTOR_TABLE__,
|
||||||
|
count = __DESTRUCTOR_COUNT__;
|
||||||
|
}
|
||||||
|
SYMBOLS {
|
||||||
|
__STACKSIZE__ = $800; # 2K stack
|
||||||
|
}
|
||||||
|
</verb></tscreen>
|
||||||
|
|
||||||
|
New contents for NEXEHDR and CHKHDR are needed (split2.s):
|
||||||
|
<tscreen><verb>
|
||||||
|
.import __CODE_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 __CODE_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 script. 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.
|
||||||
|
|
||||||
|
|
||||||
<sect>Bugs/Feedback<p>
|
<sect>Bugs/Feedback<p>
|
||||||
@@ -194,7 +398,8 @@ These are defined to be Atari + number key.
|
|||||||
If you have problems using the library, if you find any bugs, or if you're
|
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
|
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"
|
free to contact me by email (<htmlurl url="mailto:uz@cc65.org"
|
||||||
name="uz@cc65.org">).
|
name="uz@cc65.org"> or <htmlurl url="mailto:cpg@aladdin.de"
|
||||||
|
name="cpg@aladdin.de">).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user