Jump to content
IGNORED

cc65 reserving specific memory area.


TGB1718

Recommended Posts

In a program I'm writing, I want to reserve the 16K memory area @ $4000 , I've looked through the cc65

manual and found a topic which says you need a different config file and it gives an example of how to do this.

 

I've copied the example given and compiled as shown, but it throws out several errors and won't compile.

I tried changing the parameters, but can't seem to resolve the issues

 

Just wondering if anyone has used this and got it working ?

Link to comment
Share on other sites

This is what I get:-

ld65: Warning: split.cfg(49): Segment 'EXEHDR' does not exist
ld65: Warning: split.cfg(49): Segment 'MAINHDR' does not exist
ld65: Warning: split.cfg(49): Segment 'AUTOSTRT' does not exist
ld65: Warning: split.cfg(14): Segment 'CODE' overflows memory area 'RAMLO' by 5676 bytes
ld65: Error: Cannot generate most of the files due to memory area overflow 

Link to comment
Share on other sites

@ilmenit Many thanks, I did try yours, but still loads of errors similar to the example I tried

 

ld65: Warning: split.cfg(83): Segment 'FILEHDR' does not exist
ld65: Warning: split.cfg(83): Segment 'NEXEHDR' does not exist
ld65: Warning: split.cfg(83): Segment 'GFX' does not exist
ld65: Warning: split.cfg(83): Segment 'FIRST_END' does not exist
ld65: Warning: split.cfg(83): Segment 'SFX' does not exist
ld65: Warning: split.cfg(83): Segment 'CHKHDR' does not exist
ld65: Warning: split.cfg(33): Segment 'DATA' overflows memory area 'RAM' by 193 bytes
ld65: Error: Cannot generate most of the files due to memory area overflow 

Link to comment
Share on other sites

8 minutes ago, sanny said:

Most warnings can be ignored, but not the ones like "...overflows memory area...". There is not enough space in this area, you need to shuffle around and put something into other segments.

Unfortunately I have no idea how to do this :(

8 minutes ago, sanny said:

Make a verbose map file to see what things are in this overflowing area and pick some and put them into another area.

or this

Link to comment
Share on other sites

36 minutes ago, sanny said:

cl65 -tatari -C file.cfg -O -m hello.map -vm -o hello.com hello.c

 

This will create a hello.map map file.

Thank you, I now have a map and can see why there's an overflow error. not quite sure what to do about it, 

just trying to figure out where it's getting it's values from.

 

I'll go back to the original config file and see if I can fix that one

Link to comment
Share on other sites

In attachment there is a "minimalistic example" I tried to put to explain how to use the linker .CFG to generate any output that is desired. In the example the code is split into two segments:

  1. from $2000 to $4000
  2. from $8000 up

First, it's not easy to understand what's going on and took me a while to read the documentation. It's complex, but reason is that it's very flexible and allows to generate binary files for any platform, in any format. Maybe there is some other, easier way of defining it and if anybody knows I'd be grateful for this information.

 

The linker configuration file description is here https://cc65.github.io/doc/ld65.html#s5 and if you want to prepare your own unfortunately you have to understand most of it. You will also need to understand Atari executable format to build proper XEX file.

I'll try to explain here shortly how to create a file with "reserved window" $4000 to $8000 for use of Extended Memory. In fact you can put code and data also there (as long as you make sure that nothing of it is used when this memory is banked out).

Lets start then. For the first two sections of .CFG file (FEATURES and SYMBOLS) I recommend to read the manual:

# Main memory block is loaded after RMT music 
FEATURES {
    STARTADDRESS: default = $2000;
}
SYMBOLS {
    __FILEHDR__:          type = import;
    __AUTOSTART__:       type = import;  # force inclusion of autostart "trailer"
    __STACKSIZE__:       type = weak, value = $400; 
    __STARTADDRESS__:    type = export, value = %S;
    __RESERVED_MEMORY__: type = weak, value = $0000;
	__RAM_AVAIL__:       value = $BC20 - __STACKSIZE__ - __RESERVED_MEMORY__, type = weak; 
}

Writing code in CC65 for Atari you should at least understand __STACKSIZE__, __STARTADDRESS__ and __RESERVED_MEMORY__.

 

Next there is very important section MEMORY:

MEMORY {
    ZP:         file = "", define = yes, start = $0082, size = $0035;
    #  load chunk
    HEADER:     file = %O,               start = $0000, size = $0002;

    # load chunk
    FSTHDR: start = $0000, size = $4, file = %O;        
    RAM_LOW: start = %S, size = $4000 - %S, file = %O;
    
    # load chunk

    SECHDR: start = $0000, size = $4, file = %O;
    RAM_HIGH: start = $8000, size = __RAM_AVAIL__ - $8000, file = %O;

    TRAILER:    file = %O,               start = $0000, size = $0006;
}

This section is describing memory layout of your program and what is actually generated to executable file (when file = %O). MEMORY layout of chunks assures that no code/data will overwrite other memory chunks (linker will show error if you will try to put too much into one memory chunk).

 

We create two memory chunks (RAM_LOW and RAM_HIGH), where:

  • RAM_LOW will have reserved memory from STARTADDRESS $2000 up to $4000
  • RAM_HIGH will have reserved memory from $8000 up to available memory.

In the MEMORY section create the output XEX file. To understand how it works you need to understand XEX file format - it's very simple and described in many places e.g. here. We output to the file following data

1. XEX Header -> 4 bytes, $FFFF

2. First XEX Section Header for RAM_LOW -> 4 bytes that describe the memory chunk addresses

3. Data for RAM_LOW -> size depending on the code/data  

4. Second XEX Section Header for RAM_HIGH -> 4 bytes that describe the memory chunk addresses

5. Data for RAM_HIGH -> size depending on the code/data  

6. TRAILER -> RUN section that will execute your program 

 

Next we move to Segment section, that tells what is loaded to defined MEMORY chunks:

SEGMENTS {
    ZEROPAGE:  load = ZP,         type = zp;
    EXTZP:     load = ZP,         type = zp,                optional = yes;
    FILEHDR:   load = HEADER, type = ro;                     # discarded old EXE header

###########
    FIRSTHDR: load = FSTHDR, type = ro;                  # first load chunk
    FIRST_START: load = RAM_LOW, type = ro, define = yes;
    STARTUP:   load = RAM_LOW, type = ro, start=%S, define = yes;
    ONCE:      load = RAM_LOW, type = ro,                optional = yes;
    INIT:      load = RAM_LOW, type = rw,                optional = yes;
    LOWDATA:      load = RAM_LOW, type = rw, define = yes, optional = yes;
    LOWRODATA:    load = RAM_LOW, type = ro, define = yes, optional = yes;
    LOWCODE:      load = RAM_LOW, type = rw, define = yes, optional = yes;
    FIRST_END: load = RAM_LOW, type = ro, define = yes; # we are generating data up to this place
    LOWBSS:       load = RAM_LOW, type = bss, define = yes; # type=BSS section is not included into binary
###########

###########
    SECONDHDR:    load = SECHDR,    type = ro;                   # second load chunk
    SECOND_START: load = RAM_HIGH, type = ro, define = yes;
    CODE:   load = RAM_HIGH,       type = ro, define = yes;    
    DATA:   load = RAM_HIGH,       type = rw, define = yes, optional = yes; # for data out of banked area
    RODATA:    load = RAM_HIGH, type = ro, define = yes;
    SECOND_END: load = RAM_HIGH, type = ro, define = yes; # we are generating data up to this place
    BSS:       load = RAM_HIGH,       type = bss, define = yes; # type=BSS section is not included into binary
###########
    AUTOSTRT:  load = TRAILER,   type = ro;

}

To create your own you need to understand what CODE, DATA, RODATA and BSS segments are, short description is also here https://cc65.github.io/doc/ld65.html#toc5.2

What I did here is duplication of all these segments into LOW and HIGH memory areas, so a single C file can be compiled in a way that code, data, read-only data and uninitialized data defined in this C will go to selected memory chunk (LOW or HIGH). More about it later.

 

I added also two markers for each section (FIRST_START, FIRST_END and SECOND_START, SECOND_END) that allows to easily calculate amount of data for XEX Section headers (later in src/link.asm file). The markers are placed before BSS section because BSS section is "virtual" (uninitialized data is not going to executable file).

 

The FEATURES section I used the default one.

 

The next file is src/link.asm that contains helper data that is going to our XEX file:

    .import __FIRST_START_LOAD__ , __SECOND_START_LOAD__
    .import __FIRST_END_LOAD__ , __SECOND_END_LOAD__    
    .export         __FILEHDR__: absolute = 1
    .export         __FIRSTHDR__: absolute = 1
    .export         __SECONDHDR__: absolute = 1
    
; These are Atari DOS file segment headers in binary form

.segment "FILEHDR"
     .word   $FFFF

.segment "FIRSTHDR"
    .word    __FIRST_START_LOAD__
    .word    __FIRST_END_LOAD__ - 1

.segment "SECONDHDR"
    .word    __SECOND_START_LOAD__
    .word    __SECOND_END_LOAD__ - 1

; defining segments so they can be used in .CFG file

.segment "FIRST_START"
.segment "FIRST_END"
.segment "SECOND_START"
.segment "SECOND_END"


; Lets define all the segments so there is no error if e.g. there is no uninitialized data going to BSS segment from the C code
.segment "LOWBSS"
.segment "LOWCODE"
.segment "LOWDATA"
.segment "LOWRODATA"

1. We import our markers FIRST_START, FIRST_END and SECOND_START, SECOND_END from linker .CFG file so we can use them as data.

2. We define all the headers (for XEX and then for 2 XEX sections, with start and end addresses of data)

3. We define also segments that can be not used in C code yet, which would produce error about missing segments. This prevents it.

 

Now lets move to compilation. We cannot use the "basic" cl65 utility (compile and link), because it's placing code, data, bss for each file into the same memory chunks. I created a helpful .BAT file that is placing selected files into selected memory chunks. It's first compiling (cc65) the source codes to .s (asm), then performing assembling to .o (object file), and then linking everything together, with inclusion of link.asm file that has header data for our XEX.

set all_files=

for %%x in (
    src/low    
) do (
    cc65 -Cl -T -Osir --cpu 6502 -t atari --code-name "LOWCODE" --data-name "LOWDATA" --rodata-name "LOWRODATA" --bss-name "LOWBSS" %%x.c || goto :error
    ca65 -t atari %%x.s || goto :error
    set all_files=!all_files! %%x.o
)

for %%x in (
    src/main
    src/high
) do (
    cc65 -Cl -T -Osir --cpu 6502 -t atari %%x.c || goto :error
    ca65 -t atari %%x.s || goto :error
    set all_files=!all_files! %%x.o
)

ca65 -t atari src/link.asm     || goto :error
ld65 -Ln program.lbl --mapfile program.map --dbgfile program.dbg -C atari-atr.cfg -o program.xex %all_files% atari.lib src/link.o

@IF NOT EXIST program.xex (
    @echo Compilation error
    goto :error
)

Make sure that you have proper paths defined for the tools. When compiled properly we will have our source codes compiled into LOW and HIGH memory:

two-sections.png.206f111f6cf2b27e68255062bc867b63.png

In "Adam Is Me" I'm using also memory in the bank area during the main game, only making sure that when extended memory is needed (for UNDO) I'm not going to call any function there nor use any data.

two-sections.zip

Edited by ilmenit
  • Like 2
Link to comment
Share on other sites

@ilmenit, thank you for your thorough explanation.

 

Your build script could be simplified by using cl65. I don't have a Windows at hand, here are the commands I issued manually:

 

$ cl65 -c -Cl -T -Osir --cpu 6502 -t atari --code-name "LOWCODE" --data-name "LOWDATA" --rodata-name "LOWRODATA" --bss-name "LOWBSS" -o low.o src/low.c 
$ cl65 -c -Cl -T -Osir --cpu 6502 -t atari -o main.o src/main.c 
$ cl65 -c -Cl -T -Osir --cpu 6502 -t atari -o high.o src/high.c 
$ cl65 -c -Cl -T -Osir --cpu 6502 -t atari -o link.o src/link.asm 
$ cl65 -t atari -C atari-atr.cfg -o program.xex -m program.map *.o
$ ls -ltr
total 84
-rw-r--r-- 1 chris chris 18944 Dec 10  2020 chkxex.exe
-rw-r--r-- 1 chris chris   988 Nov 22 23:19 build-atari.bat
-rw-r--r-- 1 chris chris  3231 Nov 22 23:49 atari-atr.cfg
-rw-r--r-- 1 chris chris   744 Nov 23 12:18 low.o
-rw-r--r-- 1 chris chris   870 Nov 23 12:19 main.o
drwxr-xr-x 2 chris chris  4096 Nov 23 12:19 src/
-rw-r--r-- 1 chris chris   708 Nov 23 12:19 high.o
-rw-r--r-- 1 chris chris   770 Nov 23 12:19 link.o
-rw-r--r-- 1 chris chris  3236 Nov 23 12:20 program.xex
-rw-r--r-- 1 chris chris 28828 Nov 23 12:20 program.map
$ ataricom program.xex 
ataricom 0.30-150320
(c) 2008-2014 Matthias Reichl <hias@horus.com>
block    1: 2000-208e (bytes:   143, offset:      6)
block    2: 8000-8c04 (bytes:  3077, offset:    153)
block    3: 02e0-02e1 (bytes:     2, offset:   3234)
       RUN: 2001
$

 

PS: you don't need to provide your own FILEHDR, you could use the one from atari.lib.

PS2: with recent CC65 ("recent" being less that ~ 8 years old), you don't need to set CC65_xxx and LD65_xxx environment variables. Just add cc65 to your PATH.

Edited by sanny
  • Like 1
Link to comment
Share on other sites

@sanny I put your commands into a batch file, unfortunately I think it needs your atari-atr.cfg, file

all the others throw different errors about missing external.

 

The main one is __RESERVED_MEMORY__ , I put it on the command line -D__RESERVED_MEMORY__=0 

but it still fails

 

I'll keep playing, may be able to resolve it another way

Link to comment
Share on other sites

The others I used are the built in ones supplied in cc65

 

if fails with external references or missing memory areas

using atari.cfg 

 

ld65: Error: Missing memory area assignment for segment 'LOWDATA'

 

and atarixl.cfg

 

ld65: Warning: E:\Program Files (x86)\CC65/cfg/atarixl.cfg(86): Segment 'SRPREPHDR' does not exist
ld65: Warning: E:\Program Files (x86)\CC65/cfg/atarixl.cfg(86): Segment 'SRPREP' does not exist
ld65: Warning: E:\Program Files (x86)\CC65/cfg/atarixl.cfg(86): Segment 'SRPREPTRL' does not exist
Unresolved external '__RESERVED_MEMORY__' referenced in:
  atari/system_check.s(165)
  atari/system_check.s(168)
  atari/crt0.s(75)
  atari/crt0.s(79)
ld65: Error: 1 unresolved external(s) found - cannot create output file

 

 

 

 

 

 

Link to comment
Share on other sites

@TGB1718, what do you want to achieve? A program which a "hole" in the $4000-$7FFF area, correct?

 

@ilmenit showed you a working example. You could use that as a starting point to add your code. Of course, @ilmenit's program doesn't work with the cc65 supplied CFGs.

 

But you could also use the example in the cc65 docs as starting point. You haven't said what exactly is not working.

Link to comment
Share on other sites

15 minutes ago, sanny said:

what do you want to achieve? A program which a "hole" in the $4000-$7FFF area, correct?

Yes, that's what I'm trying to achieve, I'll spend today reading through and look again at the examples supplied here

and see where I get, it's obviously a complex subject

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...