6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Wed Oct 23, 2024 6:23 pm

All times are UTC




Post new topic Reply to topic  [ 10 posts ] 
Author Message
PostPosted: Fri Sep 09, 2016 4:54 pm 
Offline

Joined: Fri Sep 09, 2016 6:51 am
Posts: 5
Hi all,

I've always wanted to set up a nice hybrid C / ASM framework for my stuff on the C64, so lately I've been messing around quite intensly with cc65.

My current issue is with relocating the CODE segment to anything different than the default location set in the linker config file.
My current approach consists in changing the MEMORY section from the c64.cfg default linker config file, altering the MAIN start address as follows (MAIN is the memory area where the CODE segment, among others, is loaded):

Code:
### This is the default MAIN code segment's location from the MEMORY section of the c64.cf linker file:
#    MAIN:     file = %O, define = yes, start = __HEADER_LAST__, size = __HIMEM__ - __HEADER_LAST__;

### This is a sample of what I try to set is to:
    MAIN:     file = %O, define = yes, start = $3000, size = $4000;

The $3000 starting location set above is just an example, I've tried many different locations but the end result is always the same: my code crashes! Leaving the location to the default address, instead, everything works fine.
What's weird is that, no matter what I set the MAIN memory address to, cc65 always generates a SYS 2061 stub.

I'm not sure what I'm doing wrong, and I'm quite sure (but obviously I might be wrong) that I don't have to mess up with the LOADADDR and HEADER memory locations since that's where the EXEHDR segment is going to be located.

All help would be greatly appreciated!

Thanks in advance,
Fabrizio


Top
 Profile  
Reply with quote  
PostPosted: Fri Sep 09, 2016 8:05 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 9:02 pm
Posts: 1745
Location: Sacramento, CA
I'm away from my computer but you can look at my cc65 files for the emulator I did. It might shed some light.

http://sbc.rictor.org/download/AVR_CC65.zip

Will try to follow up this wekend.

Daryl

_________________
Please visit my website -> https://sbc.rictor.org/


Last edited by 8BIT on Sat Sep 10, 2016 5:46 am, edited 1 time in total.

Top
 Profile  
Reply with quote  
PostPosted: Fri Sep 09, 2016 9:15 pm 
Offline

Joined: Tue Jul 24, 2012 2:27 am
Posts: 679
According to the docs, you want to start with c64-asm.cfg, not c64.cfg. The latter assumes standalone RUN-launched programs.

_________________
WFDis Interactive 6502 Disassembler
AcheronVM: A Reconfigurable 16-bit Virtual CPU for the 6502 Microprocessor


Top
 Profile  
Reply with quote  
PostPosted: Sat Sep 10, 2016 7:38 am 
Offline

Joined: Fri Sep 09, 2016 6:51 am
Posts: 5
8BIT wrote:
I'm away from my computer but you can look at my cc65 files for the emulator I did. It might shed some light.

http://sbc.rictor.org/download/AVR_CC65.zip

Will try to follow up this wekend.

Thanks a lot, it's incredibly useful being able to access as many examples as possible! I'm checking your code and I'll surely learn from it :)

In the meantime I've partially solved my issue - I say partially because, while I've been able to relocate the CODE section's start address within the MAIN memory area, I still can't successfully create any new memory area at a different address than the default one. Actually, looks like any new MEMORY areas I'm creating just won't work!

So, the following works:

Code:
MEMORY {
...
# This is the default MAIN memory area, no changes here
    MAIN:     file = %O, define = yes, start = __HEADER_LAST__, size = __HIMEM__ - __HEADER_LAST__;
...
}

SEGMENTS {
    ZEROPAGE: load = ZP,       type = zp;
    LOADADDR: load = LOADADDR, type = ro;
    EXEHDR:   load = HEADER,   type = ro;
    STARTUP:  load = MAIN,     type = ro;
    LOWCODE:  load = MAIN,     type = ro,  optional = yes;
### THIS IS WHAT I'VE CHANGED: setting a start location for the segment within the MAIN memory area
    CODE:     load = MAIN, start=$3000,    type = ro;
###
    RODATA:   load = MAIN,     type = ro;
    DATA:     load = MAIN,     type = rw;
    INIT:     load = MAIN,     type = rw;
    ONCE:     load = MAIN,     type = ro,  define   = yes;
    BSS:      load = BSS,      type = bss, define   = yes;
}

So, I've just specified the start address in the CODE segment. I don't like it very much though, it doesn't look very flexible, I'm not sure where the rest of the segments following CODE are going to be placed, and overall I quite hate it :)

I can't even create new MEMORY areas and allocate SEGMENTS in there, as the following just won't work;

Code:
MEMORY {
...
   SIDTUNE:   start = $1000, size = $1000, type = ro, file = %O, fill = yes;
...
}

SEGMENTS {
...
   sidtune:    load = SIDTUNE, start=$1000, type = ro;
...
}

That's quite weird, also considering that it's exactly what the cc65 docs suggest to do for including binary data at specific addresses... (yes, I know I can relocate SID tunes, but that was not the point :) ).

Instead, if I just locate the sidtune segment withing the MAIN memory area and set a start location for it, it works fine!

Still quite puzzled :shock: :?:
I'm afraid cc65 is a great tool with very poor documentation :(

White Flame wrote:
According to the docs, you want to start with c64-asm.cfg, not c64.cfg. The latter assumes standalone RUN-launched programs.

The docs say that the c64-asm.cfg "[...]is made for assembler programmers who don't need a special setup". I'm writing a C program with some ASM parts (both inline and as separate .s source files), and the c64-asm.cfg doesn't seem to work :(

Thanks all for the support!

Fabrizio.-


Top
 Profile  
Reply with quote  
PostPosted: Sat Sep 10, 2016 10:45 pm 
Offline

Joined: Tue Jul 24, 2012 2:27 am
Posts: 679
Saying it "Just won't work" is kind of the worst call for help you can give. ;) What is it doing, and what isn't it doing? Does cc65 refuse to compile it? Does it generate a binary that has things at the wrong address? At the very least, generate a map file and see if the address ranges look correct, if it is compiling.

Remember that cc65 just concatenates compiled binary segments together into your output file(s). It pays zero attention as to the LOADed memory layout of the file. So if you have a memory area from $1000-2000, and one from $4000-5000, and you put them both into a file with a tacked-on load address of $1000, it will load both those segments contiguously into $1000-3000, with the latter half compiled so that if the code were at $4000, the addresses would be correct. This allows you to mash together stuff into banks or relocate them out of ROM to their right place or whatever you want to do with it.

I've had my disagreements with Uz in the past, where I think it's the job of the linker to set up the file format so that it loads correctly for the target platform, while his opinion was that it's the programmer's job to manually align the segments within the file, add the headers, etc. You have to do all the latter yourself.

_________________
WFDis Interactive 6502 Disassembler
AcheronVM: A Reconfigurable 16-bit Virtual CPU for the 6502 Microprocessor


Top
 Profile  
Reply with quote  
PostPosted: Sun Sep 11, 2016 3:54 pm 
Offline

Joined: Fri Sep 09, 2016 6:51 am
Posts: 5
White Flame wrote:
Saying it "Just won't work" is kind of the worst call for help you can give. ;) What is it doing, and what isn't it doing? Does cc65 refuse to compile it? Does it generate a binary that has things at the wrong address? At the very least, generate a map file and see if the address ranges look correct, if it is compiling.

Right, but my message was already long enough to scare most ppl off and so I omitted a few details! :)

Simply put, when I try to define a custom MEMORY area and try to locate a SEGMENT in there, while everything compiles and links fine the output executable seemingly won't contain my data (or code), or at least not at all in the MEMORY area I'm telling the SEGMENT to be LOAD into.

White Flame wrote:
Remember that cc65 just concatenates compiled binary segments together into your output file(s). It pays zero attention as to the LOADed memory layout of the file. So if you have a memory area from $1000-2000, and one from $4000-5000, and you put them both into a file with a tacked-on load address of $1000, it will load both those segments contiguously into $1000-3000, with the latter half compiled so that if the code were at $4000, the addresses would be correct. This allows you to mash together stuff into banks or relocate them out of ROM to their right place or whatever you want to do with it.

This is very interesting, and indeed it was not fully clear for me. So it basically means that the LOAD address of a SEGMENT is only used for relocating purposes, and not to actually place the code in the right areas - the latter would be up to me my filling gaps somehow in the final linking process... is this correct?

Thanks again!!
Fabrizio


Top
 Profile  
Reply with quote  
PostPosted: Mon Sep 12, 2016 5:46 am 
Offline

Joined: Tue Jul 24, 2012 2:27 am
Posts: 679
Right. If you look at the implementation of adding in the load address, it's in a different segment, which is blindly tacked on to the beginning of the file, shoving everything else forward by 2 bytes without affecting any addresses.

Many people who use ca65 raw end up doing something dumb like this for the load address:
Code:
  ; .cfg file
  CODE: start=$07ff  ; Say what?

  ; .asm file
  .segment "CODE"
  .word $0801  ; Load address, at "address" $07ff
  .byte  ...BASIC line at $0801...

  ; Asm code
  lda #0
  ...

hacking in the logical start address to $07ff instead of $0801, so that it can include the 2 bytes for the file's start address, because the linker doesn't put it in there for you.

Granted, because of overlays and generating multiple files from a single build, it would be a tricky thing for the linker to be able to juggle all the complex cases. But that means that there's no help even for the simple cases. If you want to align your code in the generated file, you have to make sure that the memory areas you're dumping to the file fill up the right space so that it's aligned when LOADed on the 64.

With what you have, you should snoop through memory (or the file) to see if your extra segments are in there somewhere, just at the wrong place; or if they're not in there at all.

(Also, don't worry about scaring people here with technical details. Have you looked at the SID reverse engineering thread? ;) )

_________________
WFDis Interactive 6502 Disassembler
AcheronVM: A Reconfigurable 16-bit Virtual CPU for the 6502 Microprocessor


Top
 Profile  
Reply with quote  
PostPosted: Mon Sep 12, 2016 8:03 am 
Offline

Joined: Fri Sep 09, 2016 6:51 am
Posts: 5
White Flame wrote:
Granted, because of overlays and generating multiple files from a single build, it would be a tricky thing for the linker to be able to juggle all the complex cases. But that means that there's no help even for the simple cases. If you want to align your code in the generated file, you have to make sure that the memory areas you're dumping to the file fill up the right space so that it's aligned when LOADed on the 64.

Thank you, now I have a good lead and am much more comfortable about what I'm doing. So basically we could see the MEMORY section as something where possibly all of the memory should be mapped - at least all the MEMORY that's going to contain SEGMENTS - in order to be safe about what the linker builds, right?

White Flame wrote:
With what you have, you should snoop through memory (or the file) to see if your extra segments are in there somewhere, just at the wrong place; or if they're not in there at all.

That's indeed what I've started doing :)

White Flame wrote:
(Also, don't worry about scaring people here with technical details. Have you looked at the SID reverse engineering thread? ;) )

I'll be braver next time :D :D

I'll hack some more. For now thanks a lot,
Fabrizio


Top
 Profile  
Reply with quote  
PostPosted: Mon Sep 12, 2016 1:25 pm 
Offline

Joined: Tue Jul 24, 2012 2:27 am
Posts: 679
rasty wrote:
Thank you, now I have a good lead and am much more comfortable about what I'm doing. So basically we could see the MEMORY section as something where possibly all of the memory should be mapped - at least all the MEMORY that's going to contain SEGMENTS - in order to be safe about what the linker builds, right?


MEMORY sections can freely overlap the same address ranges; this is how you build a system with overlays. Two different independent MEMORY sections could point to $c000, for instance, and they'd both happily fill up with code that works when located at $c000. You could output those sections to different files, or concatenate them into the same file, depending on how your system loaded its overlays. If you're going to burn it into a ROM chip, and have banking work on the address pins, you could easily see your overlays being laid out consecutively in the chip's storage. If you have a software overlay system where you re-load $c000 with different contents, you could put them into different files and load whichever one is appropriate.

The biggest thing is the "file" statements in MEMORY sections. That determines which sections' bytes hit which output file. The order in which MEMORY areas are listed determines the order they're written to files, for those which target the same filename.

_________________
WFDis Interactive 6502 Disassembler
AcheronVM: A Reconfigurable 16-bit Virtual CPU for the 6502 Microprocessor


Top
 Profile  
Reply with quote  
PostPosted: Mon Sep 12, 2016 3:15 pm 
Offline

Joined: Fri Sep 09, 2016 6:51 am
Posts: 5
White Flame wrote:
rasty wrote:
Thank you, now I have a good lead and am much more comfortable about what I'm doing. So basically we could see the MEMORY section as something where possibly all of the memory should be mapped - at least all the MEMORY that's going to contain SEGMENTS - in order to be safe about what the linker builds, right?


MEMORY sections can freely overlap the same address ranges; this is how you build a system with overlays. Two different independent MEMORY sections could point to $c000, for instance, and they'd both happily fill up with code that works when located at $c000. You could output those sections to different files, or concatenate them into the same file, depending on how your system loaded its overlays. If you're going to burn it into a ROM chip, and have banking work on the address pins, you could easily see your overlays being laid out consecutively in the chip's storage. If you have a software overlay system where you re-load $c000 with different contents, you could put them into different files and load whichever one is appropriate.

The biggest thing is the "file" statements in MEMORY sections. That determines which sections' bytes hit which output file. The order in which MEMORY areas are listed determines the order they're written to files, for those which target the same filename.

Got it! (in theory, now I'll move to practice) :)

Now things make more sense!!!!

Thanks a lor for the support!!!!!!

Fabrizio


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 10 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 4 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: