adapt to new segments; some other text changes
git-svn-id: svn://svn.cc65.org/cc65/trunk@4728 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
109
doc/atari.sgml
109
doc/atari.sgml
@@ -271,15 +271,15 @@ or f80.com software is missing. Of course you may use stdio.h functions.
|
|||||||
|
|
||||||
<sect1>Function keys<p>
|
<sect1>Function keys<p>
|
||||||
|
|
||||||
These are defined to be Atari + number key.
|
Function keys are mapped to Atari + number key.
|
||||||
|
|
||||||
<sect1>Reserving a memory area inside a program<label id="memhole"><p>
|
<sect1>Reserving a memory area inside a program<label id="memhole"><p>
|
||||||
|
|
||||||
The Atari 130XE maps its additional memory into CPU memory in 16K
|
The Atari 130XE maps its additional memory into CPU memory in 16K
|
||||||
chunks at address $4000 to $7FFF. One might want to
|
chunks at address $4000 to $7FFF. One might want to
|
||||||
prevent this memory area from being used by cc65. Other reasons 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
|
prevent the use of some memory area could be to reserve space for the
|
||||||
lists and screen memory.
|
buffers for display lists and screen memory.
|
||||||
<p>
|
<p>
|
||||||
The Atari executable format allows holes inside a program, e.g. one
|
The Atari executable format allows holes inside a program, e.g. one
|
||||||
part loads into $2E00 to $3FFF, going below the reserved
|
part loads into $2E00 to $3FFF, going below the reserved
|
||||||
@@ -288,7 +288,9 @@ memory area (assuming a reserved area from $4000 to
|
|||||||
$BC1F.
|
$BC1F.
|
||||||
<p>
|
<p>
|
||||||
Each load chunk of the executable starts with a 4 byte header which
|
Each load chunk of the executable starts with a 4 byte header which
|
||||||
defines its load address and size.
|
defines its load address and size. In the following linker scripts
|
||||||
|
these headers are named HEADER and SECHDR (for the MEMORY layout), and
|
||||||
|
accordingly NEXEHDR and CHKHDR (for the SEGMENTS layout).
|
||||||
<p>
|
<p>
|
||||||
<sect2>Low code and high data example<p>
|
<sect2>Low code and high data example<p>
|
||||||
Goal: Create an executable with 2 load chunks which doesn't use the
|
Goal: Create an executable with 2 load chunks which doesn't use the
|
||||||
@@ -298,14 +300,16 @@ segments should go above $7FFF.
|
|||||||
<p>
|
<p>
|
||||||
The main problem is that the EXE header generated by the cc65 runtime
|
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
|
lib is wrong. It defines a single load chunk with the sizes/addresses
|
||||||
of the LOWCODE, INIT, CODE, RODATA, and DATA segments (the whole user
|
of the STARTUP, LOWCODE, INIT, CODE, RODATA, and DATA segments (the whole user
|
||||||
program).
|
program).
|
||||||
<p>
|
<p>
|
||||||
The contents of the EXE header come from the EXEHDR segment, which is
|
The contents of the EXE header come from the EXEHDR segment, which is
|
||||||
defined in crt0.s. This cannot be changed w/o modifying and
|
defined in crt0.s. This cannot be changed without modifying and
|
||||||
recompiling the cc65 atari runtime lib. Therefore the original EXE
|
recompiling the cc65 atari runtime lib. Therefore the original EXE
|
||||||
header must be discarded. It will be replaced by a user created
|
header must be discarded. It will be replaced by a user created
|
||||||
one.
|
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 "").
|
||||||
<p>
|
<p>
|
||||||
The user needs to create a customized linker config file which adds
|
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
|
new memory areas and segments to hold the new EXE header and the
|
||||||
@@ -314,24 +318,32 @@ needs to be created which defines the contents of the new EXE header
|
|||||||
and the second load chunk header.
|
and the second load chunk header.
|
||||||
<p>
|
<p>
|
||||||
<p>
|
<p>
|
||||||
This is a modified cc65 Atari linker configuration file (split.cfg):
|
This is an example of a modified cc65 Atari linker configuration file
|
||||||
|
(split.cfg):
|
||||||
<tscreen><verb>
|
<tscreen><verb>
|
||||||
|
SYMBOLS {
|
||||||
|
__STACKSIZE__ = $800; # 2K stack
|
||||||
|
__RESERVED_MEMORY__: value = $0000, weak = yes;
|
||||||
|
}
|
||||||
|
FEATURES {
|
||||||
|
STARTADDRESS: default = $2E00;
|
||||||
|
}
|
||||||
MEMORY {
|
MEMORY {
|
||||||
ZP: start = $82, size = $7E, type = rw, define = yes;
|
ZP: start = $82, size = $7E, type = rw, define = yes;
|
||||||
|
|
||||||
HEADER: start = $0000, size = $6, file = %O; # first load chunk
|
HEADER: start = $0000, size = $6, file = %O; # first load chunk
|
||||||
RAMLO: start = $2E00, size = $1200, file = %O;
|
RAMLO: start = %S, size = $4000 - %S, file = %O;
|
||||||
|
|
||||||
BANK: start = $4000, size = $4000, file = "";
|
BANK: start = $4000, size = $4000, file = "";
|
||||||
|
|
||||||
SECHDR: start = $0000, size = $4, file = %O; # second load chunk
|
SECHDR: start = $0000, size = $4, file = %O; # second load chunk
|
||||||
RAM: start = $8000, size = $3C20, file = %O; # $3C20: matches upper bound $BC1F
|
RAM: start = $8000, size = $3C20, file = %O; # $3C20: matches upper bound $BC1F
|
||||||
TRAILER: start = $0000, size = $0006, file = %O;
|
|
||||||
}
|
}
|
||||||
SEGMENTS {
|
SEGMENTS {
|
||||||
EXEHDR: load = BANK, type = ro;
|
EXEHDR: load = BANK, type = ro;
|
||||||
|
|
||||||
NEXEHDR: load = HEADER, type = ro; # first load chunk
|
NEXEHDR: load = HEADER, type = ro; # first load chunk
|
||||||
|
STARTUP: load = RAMLO, type = ro, define = yes;
|
||||||
LOWCODE: load = RAMLO, type = ro, define = yes, optional = yes;
|
LOWCODE: load = RAMLO, type = ro, define = yes, optional = yes;
|
||||||
INIT: load = RAMLO, type = ro, optional = yes;
|
INIT: load = RAMLO, type = ro, optional = yes;
|
||||||
CODE: load = RAMLO, type = ro, define = yes;
|
CODE: load = RAMLO, type = ro, define = yes;
|
||||||
@@ -340,9 +352,10 @@ SEGMENTS {
|
|||||||
RODATA: load = RAM, type = ro, define = yes;
|
RODATA: load = RAM, type = ro, define = yes;
|
||||||
DATA: load = RAM, type = rw, define = yes;
|
DATA: load = RAM, type = rw, define = yes;
|
||||||
BSS: load = RAM, type = bss, define = yes;
|
BSS: load = RAM, type = bss, define = yes;
|
||||||
|
ZPSAVE: load = RAM, type = bss, define = yes;
|
||||||
|
|
||||||
ZEROPAGE: load = ZP, type = zp;
|
ZEROPAGE: load = ZP, type = zp;
|
||||||
AUTOSTRT: load = TRAILER, type = ro; # defines program entry point
|
AUTOSTRT: load = RAM, type = ro; # defines program entry point
|
||||||
}
|
}
|
||||||
FEATURES {
|
FEATURES {
|
||||||
CONDES: segment = RODATA,
|
CONDES: segment = RODATA,
|
||||||
@@ -354,10 +367,6 @@ FEATURES {
|
|||||||
label = __DESTRUCTOR_TABLE__,
|
label = __DESTRUCTOR_TABLE__,
|
||||||
count = __DESTRUCTOR_COUNT__;
|
count = __DESTRUCTOR_COUNT__;
|
||||||
}
|
}
|
||||||
SYMBOLS {
|
|
||||||
__STACKSIZE__ = $800; # 2K stack
|
|
||||||
__RESERVED_MEMORY__: value = $0, weak = yes;
|
|
||||||
}
|
|
||||||
</verb></tscreen>
|
</verb></tscreen>
|
||||||
<p>
|
<p>
|
||||||
|
|
||||||
@@ -366,30 +375,29 @@ 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
|
memory area isn't written to the output file. This way the contents of
|
||||||
the EXEHDR segment get discarded.
|
the EXEHDR segment get discarded.
|
||||||
<p>
|
<p>
|
||||||
The added NEXEHDR segment defines the correct EXE header. It puts only
|
The newly added NEXEHDR segment defines the correct EXE header. It
|
||||||
the CODE segment into load chunk #1 (RAMLO memory area).
|
puts the STARTUP, LOWCODE, INIT, and CODE segments, which are the
|
||||||
|
segments containing only code, into load chunk #1 (RAMLO memory area).
|
||||||
<p>
|
<p>
|
||||||
The header for the second load chunk comes from the new CHKHDR
|
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
|
segment. It puts the RODATA, DATA, BSS, and ZPSAVE segments into load
|
||||||
memory area).
|
chunk #2 (RAM memory area).
|
||||||
<p>
|
<p>
|
||||||
<p>
|
<p>
|
||||||
The contents of the new NEXEHDR and CHKHDR segments come from this
|
The contents of the new NEXEHDR and CHKHDR segments come from this
|
||||||
file (split.s):
|
file (split.s):
|
||||||
<tscreen><verb>
|
<tscreen><verb>
|
||||||
.import __LOWCODE_LOAD__, __BSS_LOAD__, __CODE_SIZE__
|
.import __CODE_LOAD__, __BSS_LOAD__, __CODE_SIZE__
|
||||||
.import __CODE_LOAD__, __DATA_LOAD__, __RODATA_LOAD__
|
.import __DATA_LOAD__, __RODATA_LOAD__, __STARTUP_LOAD__
|
||||||
|
|
||||||
.segment "NEXEHDR"
|
.segment "NEXEHDR"
|
||||||
.word $FFFF ; EXE file magic number
|
.word $FFFF
|
||||||
; 1st load chunk
|
.word __STARTUP_LOAD__
|
||||||
.word __LOWCODE_LOAD__
|
.word __CODE_LOAD__ + __CODE_SIZE__ - 1
|
||||||
.word __CODE_LOAD__ + __CODE_SIZE__ - 1
|
|
||||||
|
|
||||||
.segment "CHKHDR"
|
.segment "CHKHDR"
|
||||||
; 2nd load chunk (contains with AUTOSTRT in fact a 3rd load chunk)
|
.word __RODATA_LOAD__
|
||||||
.word __RODATA_LOAD__
|
.word __BSS_LOAD__ - 1
|
||||||
.word __BSS_LOAD__ - 1
|
|
||||||
</verb></tscreen>
|
</verb></tscreen>
|
||||||
<p>
|
<p>
|
||||||
Compile with
|
Compile with
|
||||||
@@ -400,21 +408,27 @@ cl65 -t atari -C split.cfg -o prog.com prog.c split.s
|
|||||||
<sect2>Low data and high code example<p>
|
<sect2>Low data and high code example<p>
|
||||||
|
|
||||||
|
|
||||||
Goal: Put RODATA and DATA into low memory and LOWCODE, INIT, CODE, BSS
|
Goal: Put RODATA and DATA into low memory and STARTUP, LOWCODE, INIT,
|
||||||
into high memory (split2.cfg):
|
CODE, BSS, ZPSAVE into high memory (split2.cfg):
|
||||||
|
|
||||||
<tscreen><verb>
|
<tscreen><verb>
|
||||||
|
SYMBOLS {
|
||||||
|
__STACKSIZE__ = $800; # 2K stack
|
||||||
|
__RESERVED_MEMORY__: value = $0000, weak = yes;
|
||||||
|
}
|
||||||
|
FEATURES {
|
||||||
|
STARTADDRESS: default = $2E00;
|
||||||
|
}
|
||||||
MEMORY {
|
MEMORY {
|
||||||
ZP: start = $82, size = $7E, type = rw, define = yes;
|
ZP: start = $82, size = $7E, type = rw, define = yes;
|
||||||
|
|
||||||
HEADER: start = $0000, size = $6, file = %O; # first load chunk
|
HEADER: start = $0000, size = $6, file = %O; # first load chunk
|
||||||
RAMLO: start = $2E00, size = $1200, file = %O;
|
RAMLO: start = %S, size = $4000 - %S, file = %O;
|
||||||
|
|
||||||
BANK: start = $4000, size = $4000, file = "";
|
BANK: start = $4000, size = $4000, file = "";
|
||||||
|
|
||||||
SECHDR: start = $0000, size = $4, file = %O; # second load chunk
|
SECHDR: start = $0000, size = $4, file = %O; # second load chunk
|
||||||
RAM: start = $8000, size = $3C20, file = %O; # $3C20: matches upper bound $BC1F
|
RAM: start = $8000, size = $3C20, file = %O; # $3C20: matches upper bound $BC1F
|
||||||
TRAILER: start = $0000, size = $0006, file = %O;
|
|
||||||
}
|
}
|
||||||
SEGMENTS {
|
SEGMENTS {
|
||||||
EXEHDR: load = BANK, type = ro; # discarded old EXE header
|
EXEHDR: load = BANK, type = ro; # discarded old EXE header
|
||||||
@@ -424,13 +438,14 @@ SEGMENTS {
|
|||||||
DATA: load = RAMLO, type = rw, define = yes;
|
DATA: load = RAMLO, type = rw, define = yes;
|
||||||
|
|
||||||
CHKHDR: load = SECHDR, type = ro; # second load chunk
|
CHKHDR: load = SECHDR, type = ro; # second load chunk
|
||||||
LOWCODE: load = RAM, type = ro, define = yes, optional = yes;
|
STARTUP: load = RAM, type = ro, define = yes;
|
||||||
INIT: load = RAM, type = ro, optional = yes;
|
INIT: load = RAM, type = ro, optional = yes;
|
||||||
CODE: load = RAM, type = ro, define = yes;
|
CODE: load = RAM, type = ro, define = yes;
|
||||||
|
ZPSAVE: load = RAM, type = bss, define = yes;
|
||||||
BSS: load = RAM, type = bss, define = yes;
|
BSS: load = RAM, type = bss, define = yes;
|
||||||
|
|
||||||
ZEROPAGE: load = ZP, type = zp;
|
ZEROPAGE: load = ZP, type = zp;
|
||||||
AUTOSTRT: load = TRAILER, type = ro; # defines program entry point
|
AUTOSTRT: load = RAM, type = ro; # defines program entry point
|
||||||
}
|
}
|
||||||
FEATURES {
|
FEATURES {
|
||||||
CONDES: segment = RODATA,
|
CONDES: segment = RODATA,
|
||||||
@@ -442,25 +457,21 @@ FEATURES {
|
|||||||
label = __DESTRUCTOR_TABLE__,
|
label = __DESTRUCTOR_TABLE__,
|
||||||
count = __DESTRUCTOR_COUNT__;
|
count = __DESTRUCTOR_COUNT__;
|
||||||
}
|
}
|
||||||
SYMBOLS {
|
|
||||||
__STACKSIZE__ = $800; # 2K stack
|
|
||||||
__RESERVED_MEMORY__: value = $0, weak = yes;
|
|
||||||
}
|
|
||||||
</verb></tscreen>
|
</verb></tscreen>
|
||||||
|
|
||||||
New contents for NEXEHDR and CHKHDR are needed (split2.s):
|
New contents for NEXEHDR and CHKHDR are needed (split2.s):
|
||||||
<tscreen><verb>
|
<tscreen><verb>
|
||||||
.import __LOWCODE_LOAD__, __BSS_LOAD__, __DATA_SIZE__
|
.import __STARTUP_LOAD__, __ZPSAVE_LOAD__, __DATA_SIZE__
|
||||||
.import __DATA_LOAD__, __RODATA_LOAD__
|
.import __DATA_LOAD__, __RODATA_LOAD__
|
||||||
|
|
||||||
.segment "NEXEHDR"
|
.segment "NEXEHDR"
|
||||||
.word $FFFF
|
.word $FFFF
|
||||||
.word __RODATA_LOAD__
|
.word __RODATA_LOAD__
|
||||||
.word __DATA_LOAD__ + __DATA_SIZE__ - 1
|
.word __DATA_LOAD__ + __DATA_SIZE__ - 1
|
||||||
|
|
||||||
.segment "CHKHDR"
|
.segment "CHKHDR"
|
||||||
.word __LOWCODE_LOAD__
|
.word __STARTUP_LOAD__
|
||||||
.word __BSS_LOAD__ - 1
|
.word __ZPSAVE_LOAD__ - 1
|
||||||
</verb></tscreen>
|
</verb></tscreen>
|
||||||
|
|
||||||
Compile with
|
Compile with
|
||||||
|
|||||||
Reference in New Issue
Block a user