It is currently Mon Oct 23, 2017 6:37 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 14 posts ] 
Author Message
 Post subject: ld65 madness
PostPosted: Thu Mar 07, 2013 5:47 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 3192
Location: Mountain View, CA, USA
So it's as I expected -- I have spent more time fucking around with ld65 and trying to "make it happy" than I have actually written code. I have no real issue with the assembler (ca65), just that this bloody "linker configuration" nonsense is a complete and total nightmare. I've ranted about this before in some other post some time ago -- it provides very little benefit given the nature of the platform being developed on.

To make this simple: does anyone have a ld65 configuration template for MMC3 with multiple PRG banks in use?

I'd also like someone to explain to me what the size directive in the MEMORY section of the config actually does. The documentation does not actually say; instead its "implied" or "eluded to" somehow, yet when it comes to making an actual .NES file with multiple PRG banks, it matters immensely. It seems to control the "size" of the related .scope, i.e. how much room on-disk (in file) something takes up.

Why such is called MEMORY I don't know -- oh, wait, yes I do, because the entire linker semantics and design is intended for C, not assembly.

I'm tempted to make MEMORY into something that correlates 1:1 a segment and a file, then use FILES to set all the output types to bin, then just use copy /b header.bin+prg0.bin+prg1.bin+... > test.nes to make the damn ROM image.


Top
 Profile  
 
 Post subject: Re: ld65 madness
PostPosted: Thu Mar 07, 2013 6:50 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19116
Location: NE Indiana, USA (NTSC)
You might want to start with an MMC1 project using my SGROM/SNROM template, which can be modified for UNROM with only a slight change to the code (replacing the serial load with a simple load).

I'm willing to walk you through making a working ld65 configuration file. Are you using fixed $C000/$E000 or fixed $8000/$E000? If the former, how many $8000 banks and how many $A000 banks? If the latter, how many $A000 banks and how many $C000 banks?


Top
 Profile  
 
 Post subject: Re: ld65 madness
PostPosted: Thu Mar 07, 2013 7:23 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 10:59 pm
Posts: 1390
The "size" value in MEMORY lets you control exactly how much ROM space can be used by that section - for example, if you have an 8KB bank that gets mapped at $8000-$9FFF, then you'd have "start = $8000, size = $2000" (and probably also "fill = yes" to make sure it gets padded), while a 16KB bank at $C000-$FFFF would have "start = $C000, size = $4000" (or perhaps "size = $3FFA" if it's your fixed bank and you want a separate 6-byte memory block for your interrupt vectors so you don't have to explicitly insert the padding in your code); the SEGMENTS section lets you control the order in which each block gets assembled into your resulting 'object' file (which will be your entire PRG ROM).

_________________
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.


Top
 Profile  
 
 Post subject: Re: ld65 madness
PostPosted: Thu Mar 07, 2013 7:25 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 3192
Location: Mountain View, CA, USA
I did have a "working" ld configuration file for MMC3 (well, meaning it didn't emit any errors during link-time), but the problem was that the PRG banks/pages were 4x larger than they should have been (because I had to change size=$2000 to size=$8000 in the MEMORY section), but it's become a pain in the ass for me simply because I don't understand what on earth is really going on under the hood. I say all this with familiarity with linkers and segment models on x86/x64 platforms and OSes, but the NES is not such a platform.

I started with rainwarrior's MOON8 stuff, then modified it to work with UxROM. That worked great -- no issues. But the PRG bank size on UxROM is 16KBytes, so the ld65 configuration template was much more obvious (everything having size=$4000 and start=$8000).

With MMC3, the PRG bank sizes are 8KBytes, which is inducing lots of confusion.

I'll take a look at your SGROM/SNROM template and see what I can make from that.

As for the hardwiring, I planned on having $C000/$E000 hardwired.


Top
 Profile  
 
 Post subject: Re: ld65 madness
PostPosted: Thu Mar 07, 2013 7:56 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 3192
Location: Mountain View, CA, USA
Quietust wrote:
The "size" value in MEMORY lets you control exactly how much ROM space can be used by that section - for example, if you have an 8KB bank that gets mapped at $8000-$9FFF, then you'd have "start = $8000, size = $2000" (and probably also "fill = yes" to make sure it gets padded), while a 16KB bank at $C000-$FFFF would have "start = $C000, size = $4000" (or perhaps "size = $3FFA" if it's your fixed bank and you want a separate 6-byte memory block for your interrupt vectors so you don't have to explicitly insert the padding in your code); the SEGMENTS section lets you control the order in which each block gets assembled into your resulting 'object' file (which will be your entire PRG ROM).

Thank you thank you thank you thank you! This is exactly what I needed to know -- I got everything working. :-)

Edit: removed example code. CHR-ROM stuff is not working how I expected, but that's my own fault/issue/misunderstanding.


Top
 Profile  
 
 Post subject: Re: ld65 madness
PostPosted: Thu Mar 07, 2013 8:30 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5734
Location: Canada
I find the cc65 documentation is not good at all as a tutorial, but the information I need is usually there if I look for it. If you want a good understanding of the linker config files, I suggest just giving this entire page a quick read:

http://www.cc65.org/doc/ld65-5.html

Edit: Oh, you already linked to it. Well, never mind.


Last edited by rainwarrior on Thu Mar 07, 2013 8:57 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject: Re: ld65 madness
PostPosted: Thu Mar 07, 2013 8:49 pm 
Offline
User avatar

Joined: Mon Sep 27, 2004 8:33 am
Posts: 3715
Location: Central Texas, USA
I've found cc65's documentation very lacking. I keep yelling at it, "what does this DO?" and it answers back "this is used for this kind of thing". I resorted to the scientific method to figure out the meanings of things. It's very frustrating to deal with things that aren't documented. We can't read the mind of the programmer, who of course knows what everything does. This is a common problem with software, where creators keep too much in their head and leave everyone else (including themselves at a later date) in the dark. I speak from my own past self who has left me in this position for lots of my stuff...


Top
 Profile  
 
 Post subject: Re: ld65 madness
PostPosted: Thu Mar 07, 2013 11:39 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 3192
Location: Mountain View, CA, USA
Thanks guys. :-) rainwarrior, your MOON8 stuff is really what helped me the most (when making a UxROM image), hands down. Like I read it and struggled a bit but then it made sense.

The stuff I'm stuck on now is vectors (REALLY!?!?!? THIS IS A WALK IN THE DAMN PARK), but I see this same topic has come up before -- viewtopic.php?t=8586 -- it looks like I'm going to have to do things the "hard" way and make a separate segment for them. I really hoped to just keep them in the source code of my last (hard-wired) PRG bank, but oh well.


Top
 Profile  
 
 Post subject: Re: ld65 madness
PostPosted: Fri Mar 08, 2013 5:56 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19116
Location: NE Indiana, USA (NTSC)
For vectors, make a new segment starting at $FFFA in the last bank.


Top
 Profile  
 
 Post subject: Re: ld65 madness
PostPosted: Fri Mar 08, 2013 11:25 am 
Offline
User avatar

Joined: Mon Jan 03, 2005 10:36 am
Posts: 2963
Location: Tampere, Finland
FYI, there's also the snapshot doc which contains some stuff the release doc doesn't yet (and maybe some fixed links, etc). Naturally it would make sense to use that with the snapshot version of cc65, as it might (and does) mention some features that the release version doesn't include.

Quietust wrote:
(or perhaps "size = $3FFA" if it's your fixed bank and you want a separate 6-byte memory block for your interrupt vectors so you don't have to explicitly insert the padding in your code);

It's also possible to do this by using the start attribute of the VECTORS segment, which is placed in the last bank (i.e. last ROM based MEMORY block, basically what tepples said).

It's important to note that the order of segments in the file is relevant, so if a segment has a start address of $FFFA, it must come after every other segment that goes in the same bank (otherwise the bank will get padded up to $FFFA, and rest of the segments will not fit).

_________________
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: kkfos.aspekt.fi


Top
 Profile  
 
 Post subject: Re: ld65 madness
PostPosted: Fri Mar 08, 2013 8:12 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 3192
Location: Mountain View, CA, USA
For other readers, this is what I ended up doing:

ld65 memory config (called main.cfg) --

Code:
MEMORY {
    ZP:        start = $00,   size = $100,  type = rw;
    RAM:       start = $0200, size = $600,  type = rw;
    HDR:       start = $0000, size = $10,   type = ro, file = %O, fill = yes;
    PRG0:      start = $8000, size = $4000, type = ro, file = %O, fill = yes, fillval = $FF;
    PRG1:      start = $8000, size = $4000, type = ro, file = %O, fill = yes, fillval = $FF;
    PRG2:      start = $8000, size = $4000, type = ro, file = %O, fill = yes, fillval = $FF;
    PRG3_C000: start = $C000, size = $2000, type = ro, file = %O, fill = yes, fillval = $FF;
    PRG3_E000: start = $E000, size = $2000, type = ro, file = %O, fill = yes, fillval = $FF;
    CHR0:      start = $0000, size = $1000, type = ro, file = %O, fill = yes, fillval = $00;
    CHR1:      start = $0000, size = $1000, type = ro, file = %O, fill = yes, fillval = $00;
}

SEGMENTS {
   ZP:         load = ZP,         type = zp;
   BSS:        load = RAM,        type = bss, align = $100, define = yes;
   HEADER:     load = HDR,        type = ro,  align = $10;

   PRG0_8000:  load = PRG0,       type = ro,  start = $8000;
   PRG0_A000:  load = PRG0,       type = ro,  start = $A000;
   PRG1_8000:  load = PRG1,       type = ro,  start = $8000;
   PRG1_A000:  load = PRG1,       type = ro,  start = $A000;
   PRG2_8000:  load = PRG2,       type = ro,  start = $8000;
   PRG2_A000:  load = PRG2,       type = ro,  start = $A000;
   PRG3_C000:  load = PRG3_C000,  type = ro,  start = $C000;
   PRG3_E000:  load = PRG3_E000,  type = ro,  start = $E000;
   VECTORS:    load = PRG3_E000,  type = ro,  start = $FFFA;
   CHR0:       load = CHR0,       type = ro,  define = no;
   CHR1:       load = CHR1,       type = ro,  define = no;
}

FILES {
   %O:   format = bin;
}


main.s, which is what's assembled when calling ca65:

Code:
        .setcpu "6502"

;
; NES (1.0) header
; http://wiki.nesdev.com/w/index.php/INES
;
.segment "HEADER"
        .byte "NES", $1a
        .byte $04               ; 16KB PRG-ROM banks = 4
        .byte $01               ;  8KB CHR-ROM banks = 1
        .byte $40, $00          ; Mapper 4 (MMC3)
        .byte $00
        .byte $00
        .byte $00
        .byte $00
        .byte $00
        .byte $00
        .byte $00
        .byte $00


;
; Zero page variables
;
.segment "ZP"
scroll1:        .res 1
scroll2:        .res 1


;
; PRG banks (8KBytes each, per MMC3)
;
.scope PRG0
        .segment "PRG0_8000"
        .segment "PRG0_A000"
.endscope

.scope PRG1
        .segment "PRG1_8000"
        .segment "PRG1_A000"
.endscope

.scope PRG2
        .segment "PRG2_8000"
        .segment "PRG2_A000"
.endscope

.scope PRG3_C000
        .segment "PRG3_C000"
        .include "prg3_c000.s"
.endscope

.scope PRG3_E000
        .segment "PRG3_E000"
        .include "prg3_e000.s"

        ;
        ; Labels nmi/reset/irq are part of prg3_e000.s
        ;
        .segment "VECTORS"
        .addr nmi
        .addr reset
        .addr irq
.endscope

;
; CHR banks (1 or 2KBytes each, per MMC3)
;
.scope CHR0
        .segment "CHR0"
        .incbin "font.chr"
.endscope
.scope CHR1
        .segment "CHR1"
.endscope


You can see a couple things here:

1. Code for PRG0, PRG1, and PRG2 has not been written -- instead, the linker takes care of this by filling the relevant 16KByte regions in the resulting .nes file with value $FF. When I need these PRG pages (which per MMC3 will be 8KBytes), I'll edit the ld65 memory map and change the size to $2000 and split them up much like I did with PRG3_C000 and PRG3_E000.

2. The NMI, RESET, and IRQ/BRK vectors are declared in main.s, but the labels that are referenced are in prg3_e000.s.

3. CHR0 references a 4096-byte file (font.chr) and CHR1 isn't used yet (like #1 above, te linker will fill this 4096-byte region in the resulting .nes file with $00 -- I haven't gotten around to drawing graphics for that CHR page yet).

prg3_c000.s contains literally jack squat right now --

Code:
        .org $c000

        nop
        nop
        nop
        nop
        nop


prg3_e000.s -- you can see the vector labels defined here:

Code:
        .org $e000

reset:
        sei
        cld
        ldx #$ff
        txs

;
; Infinite loop for the time being
;
:       jmp :-

nmi:
        rti

irq:
        rti


And finally how to build it (I just call this make.bat) --

Code:
@echo off
SET CC65=D:\Console\cc65

del *.o test.nes

@echo on
%CC65%\bin\ca65 main.s
%CC65%\bin\ld65 -C main.cfg -m ld65_map.txt -o test.nes main.o
@pause


What ld65_map.txt contains after a successful build:

Code:
Modules list:
-------------
main.o:
    HEADER            Offs = 000000   Size = 000010
    ZP                Offs = 000000   Size = 000002
    PRG3_C000         Offs = 000000   Size = 000005
    PRG3_E000         Offs = 000000   Size = 00009F
    VECTORS           Offs = 000000   Size = 000006
    CHR0              Offs = 000000   Size = 001000


Segment list:
-------------
Name                  Start   End     Size
--------------------------------------------
CHR0                  000000  000FFF  001000
HEADER                000000  00000F  000010
ZP                    000000  000001  000002
PRG3_C000             00C000  00C004  000005
PRG3_E000             00E000  00E09E  00009F
VECTORS               00FFFA  00FFFF  000006


Exports list:
-------------



Imports list:
-------------


Note that the reason PRG3_E000 is $9F in size is because I do have some PPU/etc. code in there which I've chose to emit from this post -- it's irrelevant to what I'm showing here. :-) I just wanted to provide folks with a working example for ca65/ld65.


Top
 Profile  
 
 Post subject: Re: ld65 madness
PostPosted: Sat Mar 09, 2013 12:10 am 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5734
Location: Canada
One thing you might want to do is make the A000 segments "optional". This would let you put more than 8k in the 8000 segment if the A000 segment is left undefined. (I use this for my "standard" NSF linker config, so I can use the DPCM segment if needed, otherwise I just let data overflow into it.)


Top
 Profile  
 
 Post subject: Re: ld65 madness
PostPosted: Sat Mar 09, 2013 3:09 am 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 3192
Location: Mountain View, CA, USA
rainwarrior wrote:
One thing you might want to do is make the A000 segments "optional". This would let you put more than 8k in the 8000 segment if the A000 segment is left undefined. (I use this for my "standard" NSF linker config, so I can use the DPCM segment if needed, otherwise I just let data overflow into it.)

Yep, I may end doing that, depending on what my needs are with what I'm writing. I'll worry about that once I get there. :-)


Top
 Profile  
 
 Post subject: Re: ld65 madness
PostPosted: Sun Oct 09, 2016 11:37 pm 
Offline

Joined: Fri Aug 29, 2014 1:45 pm
Posts: 63
Hmm, it was easier than I thought. I was expecting some huge file to deal with the banking and .NES format. It does seem that there's a few gotchas in the way that file works, though. Mostly because this tool was intended for a C compiler. ;)

I'll try this with NROM, and maybe rewrite it with unbanked PRG-ROM in mind. Thanks for sharing! Finally got inspired to go back to this recent project.

tepples:
Quote:
A basic example (NROM-128)
Ah, saw the other topic.

_________________
Idealogical
From: I have an idea. It seems logical. Thus everyone must agree.

Fail, fail, fail again. Keep trying, then maybe this damn thing will work. Eventually you might even know why it worked.


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

All times are UTC - 7 hours


Who is online

Users browsing this forum: lazerbeat, Nicole, Sumez, tokumaru, Yahoo [Bot] and 12 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:  
Powered by phpBB® Forum Software © phpBB Group