Jump to content
IGNORED

Adventures with ca65


Recommended Posts

This topic is for the discussion of programming Atari 6502 (and derivative) based apps with ca65, the cross assembler portion of cc65.

 

I happen to have just started converting all of my old Atari Macro Assembler based projects to ca65, and so far I have been delighted.

 

So read on, and if you are using ca65 as well, please share in your struggles (and joys!)

 

  • Like 1
Link to comment
Share on other sites

I may rewind to the beginning later on, but the impetus to start this thread was the simple joy I got in discovering the "scrcode" built-in macro.

 

scrcode takes regular ascii text in your source code, and converts it to the internal screen code used by the target platform, in this case Atari.

 

Here is an example of how I was setting up a screen of text with AMAC:

Xltx
	DB 'who',0,'would',0,'ever',12,0
	DB 'ever',0,'use',0,'the',0,'help'
	DB 0,'key',0,31,0

And the same text defined in ca65 with the scrcode macro:

; ----------
; XL Help Key Screen Text
;
Xltx:
	scrcode "who would ever, ever use the help key ? "

In order to make this macro available, just tell ca65 to include it with the .MACPACK directive...

.MACPACK	atari

 

Link to comment
Share on other sites

Even without using cc65, in your asm sources here are a couple of tips:

 

Do use the .code, .data, .rodata and .bss along with .zeropage

Aside from effectively labelling what the section is doing it can be handy when you want to do a cart version.

e.g. the rodata remains in ROM but the data is copied from ROM to RAM during initialisation.

with the bss section, you can just reserve space, e.g. " .res 128". Also use bss rather than declare " db 0, 0, 0, 0" etc

 

Keep sources manageable, i.e. not one big listing. Split functions into, say, functional areas.

Then manage this with the .import and .export statements.

Think of that mirroring what you would do with 'static' functions/variables in C, i.e. no-one outside of here should touch this.

I do this by collecting the exports from the .s file and putting them into a same named file with the extension .inc

Then other .s files can include this header file and so the functions (variables if you must) in that can be used.

 

Link to comment
Share on other sites

29 minutes ago, Wrathchild said:

Keep sources manageable, i.e. not one big listing. Split functions into, say, functional areas.

Then manage this with the .import and .export statements.

Think of that mirroring what you would do with 'static' functions/variables in C, i.e. no-one outside of here should touch this.

I do this by collecting the exports from the .s file and putting them into a same named file with the extension .inc

Then other .s files can include this header file and so the functions (variables if you must) in that can be used.

 

Yes. The linker is your friend, you'll notice only after you understand the whole picture. Forget "ORG" of other assemblers, this seems to be one of the most problematic hurdles...

 

regards,
chris

  • Like 1
Link to comment
Share on other sites

35 minutes ago, Wrathchild said:

along with .zeropage

Funny you bring this up, as there was some zero page stuff that was throwing me...

 

The ca65 documentation seems to imply that the zero page opcodes will only be used if you declare a label in .zeropage...

 

However... What I was seeing was that the compiler was smart enough to use the zero page (2 byte) version of LDA when the operand was in zero page, even without that directive.

 

And even more confusing, was that during my initial port from AMAC to ca65, I had been comparing the generated bytes, and it threw me off that there were cases that AMAC would generate the 3 byte version, and ca65 the 2 byte version. I think it was that AMAC would do the 2 byte version for load, but the 3 byte version for store, and ca65 was (correctly) always generating the 2 byte version.

 

So... That leaves me still confused -- why do you need to declare your labels in .zeropage when it should be obvious from the value? ie, 0x82 should use zero page opcodes without you needing to flag it... I must be missing something...

 

Link to comment
Share on other sites

1 minute ago, bhall408 said:

So... That leaves me still confused -- why do you need to declare your labels in .zeropage when it should be obvious from the value? ie, 0x82 should use zero page opcodes without you needing to flag it... I must be missing something...

 

The assembler does not know where the location of a symbol actually is. Only at link time these things are ironed out. So, if a label is not "zeropage" the assembler assumes a full 16bit address.

 

regards,
chris

  • Like 1
Link to comment
Share on other sites

3 minutes ago, sanny said:

Yes. The linker is your friend, you'll notice only after you understand the whole picture. 

I have that (embracing .o and the linker) on my "to do" list.

 

I already have my project in multiple source files, but I had been bringing them in with LINK (Amac) and .include (ca65).

 

Being a lover of C, I'm looking forward to instead having my graphics library, music library, etc, each compile to .o files, and then let the linker do the magic.

 

It is quite refreshing and powerful (treating asm more like C)

 

Link to comment
Share on other sites

2 minutes ago, bhall408 said:

Being a lover of C, I'm looking forward to instead having my graphics library, music library, etc, each compile to .o files, and then let the linker do the magic.

 

Coming from a C background, it should be quite straightforward.

 

Make multiple object files which export some "global labels". Use these labels (like function names or data declarations in C) from other source files, and the linker will resolve all cross-references.

  • Like 1
Link to comment
Share on other sites

8 minutes ago, sanny said:

 

The assembler does not know where the location of a symbol actually is. Only at link time these things are ironed out. So, if a label is not "zeropage" the assembler assumes a full 16bit address.

 

regards,
chris

So is it a bug then when ca65 is treating it as zeropage?

 

Here is my example:

000000r 1               Z0		= $95
000000r 1               Z1		= $96
000B28r 1               ; Set up display list
000B28r 1  AD 30 02             lda SDLSTL
000B2Br 1  85 95                sta Z0
000B2Dr 1  AD 31 02             lda SDLSTH
000B30r 1  85 96                sta Z1
000B32r 1  A0 06                ldy #6
000B34r 1  A9 04                lda #4

How does it know to use 0x85 for STA in that case if it isn't inferring it from the value of the label? (I presume because the label is a constant)

 

The same code assembled with AMAC though had been generating the 3 byte version, treating the address as 0x0095(2 byte operand) rather than 0x95 (1 byte operand)

 

 

Edited by bhall408
typo
Link to comment
Share on other sites

1 minute ago, bhall408 said:

How does it know to use 0x85 for STA in that case if it isn't inferring it from the value of the label? (I presume because the label is a constant)

 

In this case it knows. Because, yes, it's a constant.

 

But for something like

 

.import BLAH

lda BLAH

 

the assembler assumes 16 bit addresses. If "BLAH" is in the zero-page, you'd need to use ".importzp BLAH".

 

regards,
chris

Link to comment
Share on other sites

10 minutes ago, bhall408 said:

when ca65 is treating it as zeropage

ca65 isn't (I don't think), its just declaring a variable and assigning it the value.

 

ld65 will be making the interpretation that because its a value of < $100 and its label is being used for an absolute address 'store' that it can use the abs_zp opcode instead.

 

So this is another example of "don't declare like this". You shouldn't need to care where in zp that variable lives, let the link handle that.

 

e.g.

.zeropage

dlist_hold: .res 2

 

.code

LDA SDLSTL

STA dlist_hold

LDA SDLSTH

STA dlist_hold+1

 

Edited by Wrathchild
Link to comment
Share on other sites

Ah, found the spot  in my code where AMAC (in my opinion) screwed up:

  37EE  8D1200                      sta RTCLOK
  37F1  8D1300                      sta RTCLOK+1
  37F4  8D1400                      sta RTCLOK+2

vs same with ca65 (properly taking advantage of zero page)

0007EDr 1  85 12        		sta RTCLOK
0007EFr 1  85 13        		sta RTCLOK+1
0007F1r 1  85 14        		sta RTCLOK+2

 

Link to comment
Share on other sites

53 minutes ago, bhall408 said:

Ah, found the spot  in my code where AMAC (in my opinion) screwed up:

I guess (I have never used AMAC) that might be because the label RTCLOK was first used in the code and defined later. So, in the place where it is first referenced, it is not defined in the first pass; therefore the assembler does not know the size of the operand at that time. In this situation assemblers usually assume a 16-bit operand. Then in the second pass, when it is clear already that the label is zero-page, the assembler has either to use the size it had assumed in the first pass, or accept the new size and throw phasing error at the nearest opportunity (usually: the next labelled address).

 

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

4 minutes ago, drac030 said:

I guess (I have never used AMAC) that might be because the label RTCLOCK was first used in the code and then defined. So in the first pass it is not defined and the assembler does not know the size of the operand.

I could double check, but I'm 99% sure that is the reason... Good call!

 

When I moved from AMAC to ca65, I did make a change by taking advantage of "atari.inc" from ca65, which I include very early on, and I bet that meant that ca65 knows RTCLOK before first use, where AMAC didn't know it until much later in the 1st pass, since I think it had previously been in a file included much later.

 

Link to comment
Share on other sites

32 minutes ago, bhall408 said:

ca65 knows RTCLOK

I'm still feeling this isn't the right way to think. Take:

COLOR1 = $2C5
BLUE = $84
LDA #BLUE
STA COLOR1

Would the object file produced by ca65 state BLUE is a zp address in this case?

Or by adding the following line affect this:

STA BLUE

 

 

Edited by Wrathchild
Link to comment
Share on other sites

As the constants can be resolved by the assembler it would appear the generated assembly IS directly stated in the object file:

 

image.thumb.png.bbbaf430b789ac404003ebc6081f86df.png

 

The attached zip contains the tests and output from:

ca65 -t atari test1.s
od65 --dump-all test1.o > test1.txt
ca65 -t atari test2.s
od65 --dump-all test2.o > test2.txt
ca65 -t atari test3.s
od65 --dump-all test3.o > test3.txt

But with the test file:

COLOR1 = $2C5

    .zeropage
BLUE:    .res 1
    .code
    LDA #BLUE
    STA COLOR1
    STA BLUE

The zeropage store now will reference the zp reserved address which the linker will resolve later:

 

image.thumb.png.c0c75fb1aed10788e1c91dd0ecb1d7ed.png

 

test.zip

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...