Hi, I wanted to play around with this since some time. Recently motivated by Chris Martin's problem I've tried to make a program where code loads below $4000 (starting at $2E00) and the rest at $8000. The main problem is that the generated EXE header is wrong. It defines a single load chunk with the sizes/addresses of the code, rodata, and data segments (the whole user program). I need to have 2 load chunks, one with code and one with the rest. The contents of the EXE header come from the EXEHDR segment, which is defined in crt0.s. Since this cannot be changed w/o modifiying and recompiling the cc65 atari runtime lib, I've added a second segment NEXEHDR to the linker script, which defines the correct header. This one puts only the code segment into load chunk #1. I've also added a CHKHDR segment, which provides the contents of the header for load chunk #2. This is the modified cc65 Atari linker configuration file (split.cfg): ------------------ MEMORY { ZP: start = $82, size = $7E, type = rw, define = yes; HEADER: start = $0000, size = $6, file = %O; RAMLO: start = $2E00, size = $1200, file = %O; SECHDR: start = $0000, size = $4, file = %O; BANK: start = $4000, size = $4000, file = ""; # "" is used to discard the contents RAM: start = $8000, size = $3C20, file = %O; # $3C20: matches upper bound $BC1F } SEGMENTS { EXEHDR: load = BANK, type = wprot; NEXEHDR: load = HEADER, type = wprot; # new EXE header and 1st chunk of file data CODE: load = RAMLO, type = wprot, define = yes; CHKHDR: load = SECHDR, type = wprot; # header for 2nd chunk of file data 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; } 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 } ------------------ The contents of the old EXEHDR segment should be discarded. Therefore they're relocated into the BANK memory area, which isn't written to the output file. The contents of the new NEXEHDR and CHKHDR segments come from this file (split.s): ------------------ .import __CODE_LOAD__, __BSS_LOAD__, __CODE_SIZE__ .import __DATA_LOAD__, __RODATA_LOAD__ .segment "NEXEHDR" .word $FFFF .word __CODE_LOAD__ .word __CODE_LOAD__ + __CODE_SIZE__ - 1 .segment "CHKHDR" .word __RODATA_LOAD__ .word __BSS_LOAD__ - 1 ------------------ That's the demo program I've used: ------------------ /* $Id: mem.c,v 1.2 2004/08/01 19:50:43 chris Exp $ * * show some memory stuff * * 06-Mar-2003, chris */ #include <stdio.h> #include <conio.h> #include <atari.h> extern char _dos_type; extern unsigned char _graphmode_used; unsigned int *APPMHI = (unsigned int *)14; /* 14,15 */ unsigned char *RAMTOP = (unsigned char *)106; /* in pages */ unsigned int *LOMEM = (unsigned int *)128; /* used by BASIC */ unsigned int *MEMTOP = (unsigned int *)741; unsigned int *MEMLO = (unsigned int *)743; int main(void) { clrscr(); printf(" RAMTOP = %02X (%u) - $%04X (%u)\n", *RAMTOP, *RAMTOP, *RAMTOP * 256, *RAMTOP * 256); printf(" APPMHI = $%04X (%u)\n", *APPMHI, *APPMHI); printf(" LOMEM = $%04X (%u) <BASIC only>\n", *LOMEM, *LOMEM); printf(" MEMTOP = $%04X (%u)\n", *MEMTOP, *MEMTOP); printf(" MEMLO = $%04X (%u)\n", *MEMLO, *MEMLO); printf(" ----------------------\n"); printf(" main: $%04X (code)\n", &main); printf(" _graphmode_used: $%04X (data)\n", &_graphmode_used); printf(" _dos_type: $%04X (bss)\n", &_dos_type); if (_dos_type != 1) cgetc(); return(0); } ------------------ Compile with cl65 -t atari -C split.cfg -o mt.com mem.c split.s Running it: [snip] main: $2E8F (code) _graphmode_used: $8286 (data) _dos_type: $82D9 (bss) Nice, this seems to work. Now let's try a different configuration... Put RODATA and DATA into low memory (below $4000) and CODE with BSS into high memory (split2.cfg): ------------------ MEMORY { ZP: start = $82, size = $7E, type = rw, define = yes; HEADER: start = $0000, size = $6, file = %O; RAMLO: start = $2E00, size = $1200, file = %O; SECHDR: start = $0000, size = $4, file = %O; BANK: start = $4000, size = $4000, file = ""; # "" is used to discard the contents RAM: start = $8000, size = $3C20, file = %O; # $3C20: matches upper bound $BC1F } SEGMENTS { EXEHDR: load = BANK, type = wprot; NEXEHDR: load = HEADER, type = wprot; # new EXE header and 1st chunk of file data RODATA: load = RAMLO, type = wprot, define = yes; DATA: load = RAMLO, type = rw, define = yes; CHKHDR: load = SECHDR, type = wprot; # header for 2nd chunk of file data CODE: load = RAM, type = wprot, define = yes; BSS: load = RAM, type = bss, define = yes; ZEROPAGE: load = ZP, type = zp; AUTOSTRT: load = RAM, type = wprot; } 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 } ------------------ New contents for NEXEHDR and CHKHDR are needed (split2.s): ------------------ .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 ------------------ Compiling it with cl65 -t atari -C split2.cfg -o mt.com mem.c split2.s and running it: [snip] main: $808F (code) _graphmode_used: $3086 (data) _dos_type: $8C86 (bss) Good. Works as well :-) You have to be careful about 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 (end of RAM in theory, but on the Atari dynamically set from the APPMHI system variable). 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 you don't want to place BSS and/or the stack at the end of the program, you'll have to replace/modify some parts of the cc65 runtime lib. runtime/_heap.s defines the location of the heap and atari/crt0.s defines the location of the stack by initializing sp. I haven't tried such a configuration yet, so maybe there's something else to care about... regards, chris ---------------------------------------------------------------------- To unsubscribe from the list send mail to majordomo@musoftware.de with the string "unsubscribe cc65" in the body(!) of the mail.Received on Tue Aug 3 22:22:24 2004
This archive was generated by hypermail 2.1.8 : 2004-08-03 22:22:33 CEST