Jump to content
Sign in to follow this  
TGB1718

Graphic modes in cc65

Recommended Posts

In cc65 if you want assembly modules, I create a new file <name>.s

 

example to rotate colours in a VB routine

in your "C" file:-

 


extern void setvb(void);

 

void main(void)

{

     setvb();

more code

.

.

.

.

 

 

}

 

// in .s file

   .include "atari.inc"
   .export _setvb
 

   .proc _setvb: near
   .code
   _setvb:
         LDA #7
         LDX # >MYVB
         LDY # <MYVB
         JSR SETVBV
         RTS

MYVB:    INC 704
         JMP XITVBV
   .endproc 

 

you can also export variables to/from C/.s so no need to use the stack

Share this post


Link to post
Share on other sites

Finally figured out the ML call routine. Need to .export the routine name and either need fastcall or cdecl in with the name in the C program source. Cannot use an ___underscores___ or else it throughs a duplicate definition error. Reason why I am hard pressed to figure C is that I want to also port to NES, Commodore 64, and other platforms. 

 

Let's say I already ported some stuff over to Fast Basic and they work very well. What is great a compiled Fast Basic program does not need a Run Time and can run from SpartaDOS. C and Fast Basic, you guys have something very valuable here. 

Share this post


Link to post
Share on other sites

This drove me crazy for awhile until someone in another forum pointed out. If you need to send arguments to a subroutine, they are stored in a custom stack upper ram, (The sp Pointer) not the 6502 stack. What you need to do is .... 

_my_custom_routine:
	.export _my_custom_routine
	ldy #0
 	lda (sp),y
	sta parameter01
	ldy #2
 	lda (sp),y
	sta parameter02
	
	... processes ....

	lda sp
	adc #4
	sta sp
	bcc no_sp_hi_inc_r0
	inc sp+1
no_sp_hi_inc_r0:

 

Edited by CuloMajia

Share this post


Link to post
Share on other sites

Also remember you can export variables to your C program from an assembler module

in C use

extern char PM[10];

and use it as a normal variable

i.e. X=PM[2];

Variables have to be outside the .proc to be exported, variables inside the proc are local.

 

in assembly module

 

   .include "atari.inc"
   .export _putsprite ; export function
   .export _PM ; <<<<<<<<<<export variable

 

   .proc _putsprite: near
   .code
   _putsprite:
         LDA _source
         STA $CB
         LDA _source+1
         STA $CC

.

. MORE CODE HERE

.

         AND TEMP
         ORA PM,X ; <<<<<<<used here
         STA PM,X
         RTS 
TEMP:    .BYTE 0
COUNT:   .BYTE 0

   .endproc
PM:
_PM:      .BYTE 0,0,0,0,0,0,0,0,0,0

 

 

Share this post


Link to post
Share on other sites

You don't need the '_putsprite' after the '.code' as this is already defined by the proc line.

Alternatively, you can drop the .proc and .endproc lines and use the label, there is no rule that code needs to be wrapped like that.

         LDA _source
         STA $CB

Its unclear in the example if _source comes from this file or is an import/importzp?
 

The use of hard-coded ZP locations is not good practice to be teaching as there's potential for conflicting with a ZP segment variable.

 

As 'PM' is redundant just use '_PM' in the procedure? Plus the variables here are in the code segment, e.g. not good if you were targeting a cartridge.

 

1 hour ago, TGB1718 said:

Variables have to be outside the .proc to be exported, variables inside the proc are local.

 

That statement isn't true, where did you get that from?

I think you are mixing C scope rules as in the asm generated from C where the local variable isn't visible?
E.g.

// C file 1

void initTemp(void);
extern char TEMP;

void main(void) {
	initTemp();
	TEMP = 2;
}

// C file 2

void initTemp(void) {
    char TEMP;
    TEMP = 1;
}

which gives us:

    .import        _initTemp
    .import        _TEMP
    .export        _main

; ---------------------------------------------------------------
; void __near__ main (void)
; ---------------------------------------------------------------

.segment    "CODE"

.proc    _main: near

.segment    "CODE"

    jsr     _initTemp
    lda     #$02
    sta     _TEMP
    rts

.endproc

and here (with the --static-locals flag used)

	.export		_initTemp

; ---------------------------------------------------------------
; void __near__ initTemp (void)
; ---------------------------------------------------------------

.segment	"CODE"

.proc	_initTemp: near

.segment	"BSS"

L0002:
	.res	1,$00

.segment	"CODE"

	lda     #$01
	sta     L0002
	rts

.endproc

Which when linked gives the expected error:

Unresolved external `_TEMP' referenced in:
  test_a.s(30)

In your example, if you were to move _PM/PM before the .endproc then, yes, it would no longer be in the global scope and you see the error:

Error: Exported symbol `_PM' was never defined

But it, or in this example, TEMP can be made visible to C within the proc as follows:

(To make an export visible in C it will need to have prefixing underscore)

    .data
   .export _TEMP
_TEMP:    .BYTE 0

Therefore now from C we can do:

extern char TEMP;

void initTemp(void) {
    TEMP = 1;
}

The rights and wrong of exposing a variable within a method is something else of course.

However one legit use would be to export the label so that it is available for debugging within the emulator.

 

Edited by Wrathchild
added error from C file 1/2 example

Share this post


Link to post
Share on other sites
2 hours ago, Wrathchild said:

That statement isn't true, where did you get that from?

Was a while ago, maybe before I realised you need an underscore and not tried since then :)

 

 

 

Share this post


Link to post
Share on other sites

If you ever programmed for MS-DOS in mixed C and Assembler, the underscore is a natural thing to you...

Share this post


Link to post
Share on other sites
25 minutes ago, sanny said:

If you ever programmed for MS-DOS in mixed C and Assembler, the underscore is a natural thing to you...

Only ever mixed C and Assembler on Atari ST so never used the underscore.

 

Why is it used ? just seems to be a waste of time typing unnecessary characters, what relevance does it have ?

other than code fails to compile if it's not there.

Share this post


Link to post
Share on other sites

It's to prevent variable name collisions between 'namespaces'. Lots of systems use it still, but you only run into it when mixing direct calls into C libs or using mixed assembler, etc. I think it's actually a C convention. You should see what modern c++ does to internal names.

Edited by danwinslow
  • Like 1

Share this post


Link to post
Share on other sites

Plenty of answers on StackOverflow but as Dan says, essentially this form of name-mangling helps stop clashes with asm names.

But one of the valid reasons for me is that is also helps avoid register name conflicts (less so in 6502).

 

Say in C you wrote:

unsigned char a;
...
a *= 2;

this could translate to:

asl a

which is not what was wanted. So 'asl _a' avoids that.

(Some assemblers, e.g. in MADS the 'a' is optional in 'asl a', CA65 does require it and other assemblers even use @ for the accumulator)

 

Edited by Wrathchild

Share this post


Link to post
Share on other sites

I've noticed some things though with cc65 in assembler modules, I would expect some minor changes to

adapt the code to fit with the C portion, however, I was having a small problem so loaded the code into BUG/65

to trace the code and had a bit of trouble finding the problem area, when I did figure it out this is what I found.

this piece of code:-

 

z2:    lda #1 ;problem here ???
    and _plotx
    bne l2

 

turned into this ???

20B6   LDY  #02       A0 02
20B8   LDA  (82),Y    B1 82
20BA   AND  #01       29 01
20BC   STA  290D      8D 0D 29

Other code here

.

.

.

.

Then here

20D6   LDA  290D      AD 0D 29
20D9   BEQ  20E2      F0 07
20DB   CMP  #01       C9 01
20DD   BEQ  20F3      F0 14
20DF   JMP  2103      4C 03 21

 

even though it looks like it should work, it actually never got into one of the branches, really strange.

 

Share this post


Link to post
Share on other sites

Woah, complete lack of context here, are you asking for help, do you still have a problem or sorted it?

 

From what I can sense, you are building something with ca65 and including/linking this other things and running the binary. What are the build steps and parameters, e.g. is the optimzer involved?

 

Best thing is to reduce it down to a small project that exhibits the same issue and share the source for that.

Share this post


Link to post
Share on other sites
16 hours ago, Wrathchild said:

Woah, complete lack of context here, are you asking for help, do you still have a problem or sorted it?

Sorry, not asking for help, was just pointing out something that I spotted that I thought was rather unusual as I would

expect the .asm code to remain reasonably unchanged. 

I did do it with and without Optimiser, no change.

 

I also tried with smaller code and it produced what I expected (correct code). In the end I just gave up as it didn't seem worth 

the effort, I was just trying to speed up a "C" routine, but the increase in speed was minimal.

 

 

Share this post


Link to post
Share on other sites

ok. Well, if you want meaningful commentary, you'll need to take the time to provide context. I have no idea what you are talking about at all from your post. Glad you got it sorted tho :)

Share this post


Link to post
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...
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...