It is currently Sun Oct 22, 2017 5:06 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 18 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: Thu Jun 01, 2017 2:50 pm 
Offline
User avatar

Joined: Sat Sep 07, 2013 2:59 pm
Posts: 1404
Is there a way to use a struct from C inside the Assembly code?

When I have this in C:
Code:
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:
LDA _StructVar._Value1

I wouldn't mind having to import each variable separately:
Code:
.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:
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.

_________________
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


Top
 Profile  
 
PostPosted: Thu Jun 01, 2017 3:39 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5730
Location: Canada
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?


Top
 Profile  
 
PostPosted: Thu Jun 01, 2017 3:56 pm 
Offline
User avatar

Joined: Sat Sep 07, 2013 2:59 pm
Posts: 1404
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:
#define PlayerEnergy (&Player.Energy)
and then import this in Assembly:
Code:
.import _PlayerEnergy
LDA _PlayerEnergy

this would be fine as well.

However, something like this:
Code:
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:
.import _PlayerEnergy
LDY #0
LDA (_PlayerEnergy), Y

_________________
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


Top
 Profile  
 
PostPosted: Thu Jun 01, 2017 4:09 pm 
Offline
User avatar

Joined: Sat Sep 07, 2013 2:59 pm
Posts: 1404
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:
struct MyStruct
{
    byte Abc;
    int Def;
};

in C and like this:
Code:
.struct MyStruct
    Abc .byte
    Def .word
.endstruct

in Assembly?

_________________
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


Top
 Profile  
 
PostPosted: Thu Jun 01, 2017 4:10 pm 
Offline
User avatar

Joined: Fri Nov 19, 2004 7:35 pm
Posts: 3943
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!


Top
 Profile  
 
PostPosted: Thu Jun 01, 2017 4:25 pm 
Offline
User avatar

Joined: Sat Sep 07, 2013 2:59 pm
Posts: 1404
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.

_________________
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


Top
 Profile  
 
PostPosted: Thu Jun 01, 2017 4:30 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5730
Location: Canada
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.


Top
 Profile  
 
PostPosted: Thu Jun 01, 2017 4:42 pm 
Offline
User avatar

Joined: Sat Sep 07, 2013 2:59 pm
Posts: 1404
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:
#literal ".export PlayerEnergy = %v + %b", Player, offsetof(Character, Energy)

_________________
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


Top
 Profile  
 
PostPosted: Thu Jun 01, 2017 5:01 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5730
Location: Canada
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:
// 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.


Top
 Profile  
 
PostPosted: Thu Jun 01, 2017 5:26 pm 
Offline
User avatar

Joined: Sat Sep 07, 2013 2:59 pm
Posts: 1404
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:
typedef struct
{
    unsigned char x;
    unsigned char y;
    unsigned char color;
} pixel_t;

static pixel_t pixel;

__asm__ ("ldy #%b", offsetof(pixel_t, color));

_________________
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


Last edited by DRW on Thu Jun 01, 2017 5:28 pm, edited 1 time in total.

Top
 Profile  
 
PostPosted: Thu Jun 01, 2017 5:28 pm 
Offline
User avatar

Joined: Fri May 08, 2015 7:17 pm
Posts: 1784
Location: DIGDUG
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


Top
 Profile  
 
PostPosted: Thu Jun 01, 2017 6:46 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5730
Location: Canada
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.


Top
 Profile  
 
PostPosted: Thu Jun 01, 2017 7:36 pm 
Offline
User avatar

Joined: Thu Mar 31, 2016 11:15 am
Posts: 199
Who needs macros when you can do this?

Code:
; 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.


Top
 Profile  
 
PostPosted: Thu Jun 01, 2017 7:37 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5730
Location: Canada
Ha! That's devious.

CC65 doesn't appear to like an empty ; within a struct definition though.


Top
 Profile  
 
PostPosted: Thu Jun 01, 2017 7:50 pm 
Offline
User avatar

Joined: Thu Mar 31, 2016 11:15 am
Posts: 199
Hmm. This maybe?
Code:
; 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.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 18 posts ]  Go to page 1, 2  Next

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 5 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group