Constant value for both, C and Assembly

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems.

Moderator: Moderators

User avatar
DRW
Posts: 2070
Joined: Sat Sep 07, 2013 2:59 pm

Constant value for both, C and Assembly

Post by DRW »

What do I have to do if I want to use the same constant value in both, my C and Assembly code? (I'm using of course CC65.)

In Assembly, I would write this:

Code: Select all

GAMESTATE_TITLE = $01
GAMESTATE_RUNNING = $02
And in C, I would write this:

Code: Select all

#define GAMESTATE_TITLE 0x01
#define GAMESTATE_RUNNING 0x02
But how can I make these values known in both code files without declaring them twice?

O.k., I could declare a constant in C:

Code: Select all

const unsigned char GAMESTATE_TITLE = 0x01;
const unsigned char GAMESTATE_RUNNING = 0x02;
This then translates to an actual memory address which can be used in Assembly:

Code: Select all

_GAMESTATE_TITLE:
  .byte $01
_GAMESTATE_RUNNING:
  .byte $02[/quote]

But that's the problem: A const would occupy actual space in the ROM. And this is what I don't want since my constants are just supposed to be possible values for a variable.
Sure, I want them to be declared in one location in the source code, so in case the value changes, I only have to change it in one location.
But in the actual compiled binary, all comparisons shall of course work directly with the numeric value (i.e. the value appears more than once in the ROM), not with a value at an address in the ROM.

Is there a possibility to do this?
Available now: My game "City Trouble".
Website: https://megacatstudios.com/products/city-trouble
Trailer: https://youtu.be/IYXpP59qSxA
Gameplay: https://youtu.be/Eee0yurkIW4
German Retro Gamer article: http://i67.tinypic.com/345o108.jpg
User avatar
Kasumi
Posts: 1293
Joined: Wed Apr 02, 2008 2:09 pm

Re: Constant value for both, C and Assembly

Post by Kasumi »

Part of your question may be cc65 specific. But just for reference, you precede your constants with #.

Code: Select all

jumpspeed = 6

lda jumpspeed;becomes lda $06
;It loads from the value stored in RAM location $06

lda #jumpspeed;becomes lda #$06
;It loads the value 6.
In this way, jumpspeed = 6 doesn't take up any actual memory. All it does is tell the assembler to replace any instance of jumpspeed with 6. The # tells the assembler to interpret 6 as a constant.
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Constant value for both, C and Assembly

Post by tokumaru »

Kasumi wrote:The # tells the assembler to interpret 6 as a constant.
Conceptually, maybe, but strictly speaking, the # means that the operand is an immediate value, rather than an address.

I don't think this has much to do with his problem though, which is avoiding have to declare the constants twice. I don't know anything about using C on the 6502, so I can't really help with that, sorry.
User avatar
DRW
Posts: 2070
Joined: Sat Sep 07, 2013 2:59 pm

Re: Constant value for both, C and Assembly

Post by DRW »

@Kasumi: Thanks, but I already knew this. It doesn't help me with my problem, though.

My problem is:
I want a constant that doesn't occupy any actual memory, but that gets replaced by the actual numerical value when the code is parsed. (I.e. like the one in your example.)
But I want to use the constant in both, Assembly and C. (And in C, it shall not occupy any actual memory either, but being replaced as well.)
Available now: My game "City Trouble".
Website: https://megacatstudios.com/products/city-trouble
Trailer: https://youtu.be/IYXpP59qSxA
Gameplay: https://youtu.be/Eee0yurkIW4
German Retro Gamer article: http://i67.tinypic.com/345o108.jpg
User avatar
thefox
Posts: 3139
Joined: Mon Jan 03, 2005 10:36 am
Location: Tampere, Finland
Contact:

Re: Constant value for both, C and Assembly

Post by thefox »

I'm not aware of any standardized "best" way to do this, but you are correct that it is good practice to not define the same constants in two different places.

You could possibly try using the C preprocessor to generate the include files (one for assembly, one for C) out of a single file that defines the constants. Another option would be to write a simple script that converts (or generates) the file that defines the constants... not really sure what would be the most convenient way.

In another project I used the build tools (CMake) to generate the constant headers for different languages, but it's not always practical.

EDIT: Example of using the C preprocessor:

Code: Select all

#ifdef ASM_TARGET
#define DEF_CONST(name, value) name = value
#else
#define DEF_CONST(name, value) enum { name = value };
#endif

DEF_CONST(MY_CONSTANT, 123)
DEF_CONST(ANOTHER_CONSTANT, 555)
Then you'd run this file through the C preprocessor with ASM_TARGET defined (to generate the assembly header). You could use it in the C source as is (just leave ASM_TARGET undefined when you include it).

Note that I used enum{} to define the constant in C, because it's not possible to to #define within a #define, and using enum has some other advantages also.
Last edited by thefox on Sun Aug 02, 2015 4:45 pm, edited 1 time in total.
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: fo.aspekt.fi
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Constant value for both, C and Assembly

Post by tepples »

DRW wrote:What do I have to do if I want to use the same constant value in both, my C and Assembly code? (I'm using of course CC65.)

In Assembly, I would write this:

Code: Select all

GAMESTATE_TITLE = $01
GAMESTATE_RUNNING = $02
And in C, I would write this:

Code: Select all

#define GAMESTATE_TITLE 0x01
#define GAMESTATE_RUNNING 0x02
But how can I make these values known in both code files without declaring them twice?
In ca65, .global makes a symbol available to other translation units or makes a symbol from another translation unit available to this one. Put something like this in a file you .include from everything else:

Code: Select all

.global GAMESTATE_TITLE, GAMESTATE_RUNNING
I'm not entirely sure how this appears to C programs though because I haven't really tried cc65.
User avatar
thefox
Posts: 3139
Joined: Mon Jan 03, 2005 10:36 am
Location: Tampere, Finland
Contact:

Re: Constant value for both, C and Assembly

Post by thefox »

tepples wrote:I'm not entirely sure how this appears to C programs though because I haven't really tried cc65.
It is possible to import the symbols in C code, but this has the disadvantage that the compiler can't take advantage of knowing the symbol's value when it generates the object code.
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: fo.aspekt.fi
User avatar
rainwarrior
Posts: 8062
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Constant value for both, C and Assembly

Post by rainwarrior »

Myself, when I needed this, I just put all my constants in a header file, and then wrote a little python program to parse that header and dump out an assembly equivalent. (It's not a full C parser or anything, just one that knows how I lay out that particular header file. Very simple.)
User avatar
Dwedit
Posts: 4470
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Re: Constant value for both, C and Assembly

Post by Dwedit »

Or even use the constants file as a bunch of #defines, and use the C preprocessor on ASM code.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
User avatar
DRW
Posts: 2070
Joined: Sat Sep 07, 2013 2:59 pm

Re: Constant value for both, C and Assembly

Post by DRW »

I'll get back to all your answers soon, but in the meantime I need to know:
Dwedit wrote:Or even use the constants file as a bunch of #defines, and use the C preprocessor on ASM code.
What do you mean?
Available now: My game "City Trouble".
Website: https://megacatstudios.com/products/city-trouble
Trailer: https://youtu.be/IYXpP59qSxA
Gameplay: https://youtu.be/Eee0yurkIW4
German Retro Gamer article: http://i67.tinypic.com/345o108.jpg
User avatar
Dwedit
Posts: 4470
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Re: Constant value for both, C and Assembly

Post by Dwedit »

Just a crazy idea, but if you use the C preprocessor on Assembly code (and have a build system that can call the C preprocessor an ASM code, then build that as assembly), you can use C preprocessor stuff such as #define, #include, and #ifdef in ASM code. C preprocessor is just text substitution.

It would probably just be better to simply have an assembler that already supports the C preprocessor keywords, like #define and #include, and the 0x hex prefix.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
User avatar
Bregalad
Posts: 8036
Joined: Fri Nov 12, 2004 2:49 pm
Location: Caen, France

Re: Constant value for both, C and Assembly

Post by Bregalad »

Dwedit wrote:Just a crazy idea, but if you use the C preprocessor on Assembly code (and have a build system that can call the C preprocessor an ASM code, then build that as assembly), you can use C preprocessor stuff such as #define, #include, and #ifdef in ASM code. C preprocessor is just text substitution.
Yes and no. It also diagnostics some errors (such as including a nonexistant file), and can issue warnings for newer versions of GCC. It also removes C-style comments, and add indications about line number and file where code is present.
User avatar
DRW
Posts: 2070
Joined: Sat Sep 07, 2013 2:59 pm

Re: Constant value for both, C and Assembly

Post by DRW »

Alright, I've read your messages and now I have a question:
How do I run the preprocessor?

So, let's say I have a file "Code1.c" and "Code2.s" in CC65. Now I have a header file where I write this:

Code: Select all

#ifdef ASM_TARGET
#define DEF_CONST(name, value) name = value
#else
#define DEF_CONST(name, value) enum { name = value };
#endif

DEF_CONST(MY_CONSTANT, 123)
DEF_CONST(ANOTHER_CONSTANT, 555)
I know how #ifdef etc. works and how to set preprocessor objects for the compiler. But how do I get the compiler to accept the input for the Code2.s file? In Assembly language, #define etc. aren't accepted. So, is there a command line option in the compiler that generates another code file?
rainwarrior wrote:Myself, when I needed this, I just put all my constants in a header file, and then wrote a little python program to parse that header and dump out an assembly equivalent.
O.k., writing another program that takes, for example, a CSV file and then transforms the values to C macros and Assembly constants, that's always possible. But I'd like to find a way where the codes are just there, so that you can compile them. If I can avoid it, I wouldn't want to include a dependency to another tool that generates the code files.
Available now: My game "City Trouble".
Website: https://megacatstudios.com/products/city-trouble
Trailer: https://youtu.be/IYXpP59qSxA
Gameplay: https://youtu.be/Eee0yurkIW4
German Retro Gamer article: http://i67.tinypic.com/345o108.jpg
Gered
Posts: 9
Joined: Mon Mar 16, 2015 11:03 am

Re: Constant value for both, C and Assembly

Post by Gered »

If I have code.s:

Code: Select all

#ifdef ASM_TARGET
#define DEF_CONST(name, value) name = value
#else
#define DEF_CONST(name, value) enum { name = value };
#endif

DEF_CONST(MY_CONSTANT, 123)
DEF_CONST(ANOTHER_CONSTANT, 555)
Then I can do:

Code: Select all

$ cc65 -E code.s
Which spits out the preprocessed result into code.i by default:

Code: Select all

enum { MY_CONSTANT = 123 };
enum { ANOTHER_CONSTANT = 555 };
But if I do:

Code: Select all

$ cc65 -DASM_TARGET -E code.s
I get this in code.i

Code: Select all

MY_CONSTANT = 123
ANOTHER_CONSTANT = 555
User avatar
DRW
Posts: 2070
Joined: Sat Sep 07, 2013 2:59 pm

Re: Constant value for both, C and Assembly

Post by DRW »

I'll try this out. Thanks.
Available now: My game "City Trouble".
Website: https://megacatstudios.com/products/city-trouble
Trailer: https://youtu.be/IYXpP59qSxA
Gameplay: https://youtu.be/Eee0yurkIW4
German Retro Gamer article: http://i67.tinypic.com/345o108.jpg
Post Reply