From: cpg Date: Tue, 14 Sep 2004 20:56:07 +0000 (+0000) Subject: add example of a memory configuration with holes; add cpg@aladdin.de X-Git-Tag: V2.12.0~655 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=c876758407e26add6c2766e8e06decfdf09b9ff0;p=cc65 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 --- diff --git a/doc/atari.sgml b/doc/atari.sgml index e1a8d672a..6554701d6 100644 --- a/doc/atari.sgml +++ b/doc/atari.sgml @@ -5,7 +5,7 @@ Atari specific information for cc65 <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"> -<date>16-Oct-2003 +<date>14-Sep-2004 <abstract> 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 Atari target is a machine language program with a standard executable -header (FF FF <start address> <end address>). These values are -calculated in the crt0.s file from the __CODE_LOAD__ and __BSS_LOAD__ -values, so keep this in mind if you create a custom linker config file -and start moving segments around. 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 __CODE_LOAD__ in crt0.s also. +header (FF FF <2 byte start address> <2 bytes end address> +[program bytes]). These values are calculated in the crt0.s +file from the __CODE_LOAD__ and __BSS_LOAD__ values, so keep this in +mind 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 +__CODE_LOAD__ in crt0.s. <sect>Memory layout<p> @@ -71,7 +73,8 @@ Special locations: accomodates 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. + 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 @@ -187,6 +190,207 @@ platform. There is a static driver you can use. 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> @@ -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 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">). +name="uz@cc65.org"> or <htmlurl url="mailto:cpg@aladdin.de" +name="cpg@aladdin.de">).