using structs from C in Assembly

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems. See the NESdev wiki for more information.

Moderator: Moderators

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

using structs from C in Assembly

Post by DRW »

Is there a way to use a struct from C inside the Assembly code?

When I have this in C:

Code: Select all

struct MyStruct
{
    unsigned char Value1;
    unsigned char Value2;
    unsigned char Value3;
};

struct MyStruct StructVar;
then I'd like to do something like this in Assembly:

Code: Select all

LDA _StructVar._Value1
I wouldn't mind having to import each variable separately:

Code: Select all

.import _StructVar._Value1
.import _StructVar._Value2
.import _StructVar._Value3
But one thing I wouldn't want to do is using absolute address offsets, the way the automatically generated code does it:

Code: Select all

LDA _StructVar + 1 ; Load StructVar.Value2
Because that's just crap since you have to manually keep an eye on every possible reordering of the variables.
My game "City Trouble":
Gameplay video: https://youtu.be/Eee0yurkIW4
Download (ROM, manual, artworks): http://www.denny-r-walter.de/city.html
User avatar
rainwarrior
Posts: 8734
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: using structs from C in Assembly

Post by rainwarrior »

ca65 does have a .struct directive that you can use to duplicate the C structure definition and use it in assembly.

http://cc65.github.io/doc/ca65.html#structs

The C compilation doesn't appear to use .struct in its generated code, so there's no automatic pass-through of the definition, but you could maybe make macros for C and assembly that let you include the same header in C and assembly at the same time?
User avatar
DRW
Posts: 2225
Joined: Sat Sep 07, 2013 2:59 pm

Re: using structs from C in Assembly

Post by DRW »

That's not really what I'm talking about.

Duplicating a struct would require manual synchronization between the two definitions just as well.
I would have to declare a struct in C and the same struct in Assembly again and pay attention that every little change is carried over from one struct to the other one.

I'm talking about a way of importing the separate members of a C struct into Assembly.

If I have a struct called Character and the character has a member named Energy and I have a global variable called Player, then I want to be able to use something like Player.Energy inside Assembly and let the compiler/linker find out what actual address this is.

Alternately, I would also be content with building something with the help of C preprocessors etc.
For example, if I could do something like this in C:

Code: Select all

#define PlayerEnergy (&Player.Energy)
and then import this in Assembly:

Code: Select all

.import _PlayerEnergy
LDA _PlayerEnergy
this would be fine as well.

However, something like this:

Code: Select all

byte *const PlayerEnergy = &Player.Energy;
(or however a pointer has to be declared whose address is fixed, but whose value can be written)
would not be good.
Because not only does the pointer occupy actual space in ROM, but in Assembly, I would have to use it this way:

Code: Select all

.import _PlayerEnergy
LDY #0
LDA (_PlayerEnergy), Y
My game "City Trouble":
Gameplay video: https://youtu.be/Eee0yurkIW4
Download (ROM, manual, artworks): http://www.denny-r-walter.de/city.html
User avatar
DRW
Posts: 2225
Joined: Sat Sep 07, 2013 2:59 pm

Re: using structs from C in Assembly

Post by DRW »

About using the same header file: This could be quite a hassle, right?

I mean, how do you create a file that looks like this:

Code: Select all

struct MyStruct
{
    byte Abc;
    int Def;
};
in C and like this:

Code: Select all

.struct MyStruct
    Abc .byte
    Def .word
.endstruct
in Assembly?
My game "City Trouble":
Gameplay video: https://youtu.be/Eee0yurkIW4
Download (ROM, manual, artworks): http://www.denny-r-walter.de/city.html
User avatar
Dwedit
Posts: 4924
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Re: using structs from C in Assembly

Post by Dwedit »

You can keep using the + 1 type of notation, but change the 1 into an equate for the member offset. Name it something like _VALUE1 or something, so you use someStruct + _VALUE1.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
User avatar
DRW
Posts: 2225
Joined: Sat Sep 07, 2013 2:59 pm

Re: using structs from C in Assembly

Post by DRW »

This doesn't really solve the problem, though. You still have to keep everything in sync with each other and have a redundancies in your code.
My game "City Trouble":
Gameplay video: https://youtu.be/Eee0yurkIW4
Download (ROM, manual, artworks): http://www.denny-r-walter.de/city.html
User avatar
rainwarrior
Posts: 8734
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: using structs from C in Assembly

Post by rainwarrior »

Well, if you don't like the macro suggestion I made in my first post...

You can export some structure member location from your assembly file and use asserts to make sure they are equivalent to the redundant structure definition. You'd have two definitions to maintain but you'd know immediately when they don't match.
User avatar
DRW
Posts: 2225
Joined: Sat Sep 07, 2013 2:59 pm

Re: using structs from C in Assembly

Post by DRW »

Well, I can try the macro version and try to build something with it. But everything else isn't really that elegant.

Actually, this would have been a task for the compiler: Exporting the offsets for struct members.
But the inline assembly doesn't even allow statements like ".export".

Is there some command in C that forces the compiler to include a literal statement which is ignored when checking the C syntax, but that gets written into the Assembly file as-is?
Similar to inline-assembly, only that it isn't checked for correct syntax by the C compiler and only gets checked when the assembly code gets handled.
Something like this:

Code: Select all

#literal ".export PlayerEnergy = %v + %b", Player, offsetof(Character, Energy)
My game "City Trouble":
Gameplay video: https://youtu.be/Eee0yurkIW4
Download (ROM, manual, artworks): http://www.denny-r-walter.de/city.html
User avatar
rainwarrior
Posts: 8734
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: using structs from C in Assembly

Post by rainwarrior »

I don't think C has the capability to export a constant like that. Anything that's not static is automatically exported, but I think all exports are either addresses of variables or functions, so I can't think of a way to pass a particular constant directly to the linker for use via assembly.

You could do something like this:

Code: Select all

// store the structure member offset in a variable
const void* const mystruct_member = &((struct mystruct *)NULL)->member;

; fetch from that variable in assembly:
.import _mystruct_member
ldy _mystruct_member
lda mystruct_instance, Y
Not has good as being able to ldy immediate, or skip using Y entirely, but you can at least fetch it from the variable at runtime.
User avatar
DRW
Posts: 2225
Joined: Sat Sep 07, 2013 2:59 pm

Re: using structs from C in Assembly

Post by DRW »

Yeah, I try to avoid these kinds of things: Storing values into the DATA or RAM segment that could usually be used directly. Or using the X or Y register for values that are known at compile time.

After all, my problem is really just a code style issue. And I don't like to complicate the behavior of the program, just so that I can enforce a certain style on the source code level.
(I'd rather abolish the struct altogether and simply use a bunch of separate variables. At least this would be a workaround purely on the code level while the ROM would still work exactly the same.

Also, some of my structs are not just structs, but structs with arrays inside (as a quicker alternative to an array of structs). So, the X or Y register is often already needed for the actual array index. Therefore, using it for an offset that's known at compile-time is not only ugly, but pretty much impossible.

I solved my current problem by writing the function inside C, but with 100 % inline assembly. This way, I can use the member names to turn their offsets into the literal values, like in the example from the compiler documentation:

Code: Select all

typedef struct
{
    unsigned char x;
    unsigned char y;
    unsigned char color;
} pixel_t;

static pixel_t pixel;

__asm__ ("ldy #%b", offsetof(pixel_t, color));
Last edited by DRW on Thu Jun 01, 2017 5:28 pm, edited 1 time in total.
My game "City Trouble":
Gameplay video: https://youtu.be/Eee0yurkIW4
Download (ROM, manual, artworks): http://www.denny-r-walter.de/city.html
User avatar
dougeff
Posts: 3079
Joined: Fri May 08, 2015 7:17 pm

Re: using structs from C in Assembly

Post by dougeff »

I would have done what Dwedit suggested.

MyStruct: .res 3

Value1 = 0
Value2 = 1
Value3 = 2

Then in the asm code...

(MyStruct.Value2 = 1)...

LDA #1
STA MyStruct+Value2
nesdoug.com -- blog/tutorial on programming for the NES
User avatar
rainwarrior
Posts: 8734
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: using structs from C in Assembly

Post by rainwarrior »

DRW wrote:About using the same header file: This could be quite a hassle, right?

I mean, how do you create a file that looks like this:

(example omitted)
Thinking about it some more, I believe it's doable but the fact that ca65 macros have no () enclosing parameters would make any attempted solution a little hairy.

You could also make a separate structure definitions header file with just the C or assembly structures in it and write a little parser utility to convert it to the other. You don't need a very complicated parser just to translate a struct definition.


It seems like it would be useful to be able to .export a constant from C with a #pragma or something. Might be worth making a feature request at its github project.
User avatar
pubby
Posts: 583
Joined: Thu Mar 31, 2016 11:15 am

Re: using structs from C in Assembly

Post by pubby »

Who needs macros when you can do this?

Code: Select all

; typedef struct { /*
.struct MyStruct ; */
    ; byte Abc; /*
    Abc .byte ; */
    ; byte Def; /*
    Def .word ; */
    ; unsigned char color; /* 
.endstruct ;*/ } pixel_t;
Requires your C compiler to allow empty ';' statements though.
User avatar
rainwarrior
Posts: 8734
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: using structs from C in Assembly

Post by rainwarrior »

Ha! That's devious.

CC65 doesn't appear to like an empty ; within a struct definition though.
User avatar
pubby
Posts: 583
Joined: Thu Mar 31, 2016 11:15 am

Re: using structs from C in Assembly

Post by pubby »

Hmm. This maybe?

Code: Select all

; typedef struct { /*
.struct MyStruct ; */ byte Abc; /*
    Abc .byte ; */ byte Def; /*
    Def .word ;
.endstruct ;*/ } pixel_t;
I'd test this silliness but I don't have CC65 on this computer.
Post Reply