This page is a mirror of Tepples' nesdev forum mirror (URL TBD).
Last updated on Oct-18-2019 Download

Constant value for both, C and Assembly

Constant value for both, C and Assembly
by on (#152251)
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:
GAMESTATE_TITLE = $01
GAMESTATE_RUNNING = $02


And in C, I would write this:
Code:
#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:
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]_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?
Re: Constant value for both, C and Assembly
by on (#152253)
Part of your question may be cc65 specific. But just for reference, you precede your constants with #.

Code:
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.
Re: Constant value for both, C and Assembly
by on (#152256)
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.
Re: Constant value for both, C and Assembly
by on (#152258)
@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.)
Re: Constant value for both, C and Assembly
by on (#152260)
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:
#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.
Re: Constant value for both, C and Assembly
by on (#152261)
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:
GAMESTATE_TITLE = $01
GAMESTATE_RUNNING = $02


And in C, I would write this:
Code:
#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:
.global GAMESTATE_TITLE, GAMESTATE_RUNNING

I'm not entirely sure how this appears to C programs though because I haven't really tried cc65.
Re: Constant value for both, C and Assembly
by on (#152264)
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.
Re: Constant value for both, C and Assembly
by on (#152342)
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.)
Re: Constant value for both, C and Assembly
by on (#152349)
Or even use the constants file as a bunch of #defines, and use the C preprocessor on ASM code.
Re: Constant value for both, C and Assembly
by on (#152351)
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?
Re: Constant value for both, C and Assembly
by on (#152362)
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.
Re: Constant value for both, C and Assembly
by on (#152387)
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.
Re: Constant value for both, C and Assembly
by on (#152667)
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:
#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.
Re: Constant value for both, C and Assembly
by on (#152708)
If I have code.s:

Code:
#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:
$ cc65 -E code.s


Which spits out the preprocessed result into code.i by default:

Code:
enum { MY_CONSTANT = 123 };
enum { ANOTHER_CONSTANT = 555 };


But if I do:

Code:
$ cc65 -DASM_TARGET -E code.s


I get this in code.i

Code:
MY_CONSTANT = 123
ANOTHER_CONSTANT = 555
Re: Constant value for both, C and Assembly
by on (#152793)
I'll try this out. Thanks.
Re: Constant value for eats, Shoots and Leaves
by on (#153355)
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:
GAMESTATE_TITLE = $01
GAMESTATE_RUNNING = $02


And in C, I would write this:
Code:
#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:
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:
_GAMESTATE_TITLE:
  .byte $01
_GAMESTATE_RUNNING:
  .byte $02


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?

lol comma