nesdev.com
http://forums.nesdev.com/

Accessing C struct members from Assembly?
http://forums.nesdev.com/viewtopic.php?f=2&t=18045
Page 1 of 1

Author:  gauauu [ Fri Nov 16, 2018 1:28 pm ]
Post subject:  Accessing C struct members from Assembly?

I'm curious if cc65/ca65 has a method for accessing C struct members by name from assembly. I looked through the docs and didn't find anything.

Here's an example of what I mean:
Code:
struct Foo {
  char x;
  char y;
  char z;
}

struct Foo myFoo;


Now later in assembly, I want to access myFoo.y without knowing the position of y in Foo. If I know that it's the 2nd member, it's easy to do:

Code:
 lda _myFoo+1



But is there any notation for accessing it by name y? I know there are also structs in ca65, but I don't know any way to make a struct available to both C and assembly without building my own preprocessor to generate the code for one or the other.

(I know I can completely rework things, using structs of arrays instead of an array of structs, etc. I know there's many reasons not to do what I'm doing in 6502. I'm not asking about those here. I'm just curious if there's a way to let assembly know about the ordering of members so that if I add a member w in Foo, before x, my assembly code won't need to be updated.)

Author:  dougeff [ Fri Nov 16, 2018 1:50 pm ]
Post subject:  Re: Accessing C struct members from Assembly?

You could define some constants to make the code clearer.

x = 0
y = 1
z = 2

So
lda _myFoo+1
becomes
lda _myFoo+y

*x, y, z are not good variable names

Author:  gauauu [ Fri Nov 16, 2018 2:18 pm ]
Post subject:  Re: Accessing C struct members from Assembly?

dougeff wrote:
You could define some constants to make the code clearer.

x = 0
y = 1
z = 2

So
lda _myFoo+1
becomes
lda _myFoo+y

Yeah, that's what I've done in the past. It still requires me modifying all the constants if I insert a member w. Worst comes to worst, I can write a pre-processor that generates all those constants for me, but I'd hate to do that if cc65 already provides a mechanism to do this.

Quote:
*x, y, z are not be good variable names


Absolutely, they're just placeholders to illustrate the problem. Like Foo.

Author:  yaros [ Fri Nov 16, 2018 3:58 pm ]
Post subject:  Re: Accessing C struct members from Assembly?

I know you can use "offsetof" when you use inline assembly. But it doesn't seem that cc65 export symbols with the offsets.

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));
        __asm__ ("lda %v,y", pixel);


Edit:

I looked around, there doesn't seem to be a way to output arbitrary text into the assembler file. __asm__ always validates to make sure it it only has mnemonics.

Author:  yaros [ Fri Nov 16, 2018 5:27 pm ]
Post subject:  Re: Accessing C struct members from Assembly?

Okay, so here we go. This is the time of wonderful hacks, and you have every right to throw a boot at me. I don't think it is how you should do it, but you CAN do it.

Lets imagine you have your header where you only define structs.

struct.h
Code:
typedef struct MyFoo
{
    char i;
    char d;
} MyFoo;


You use it in your C code and everything is fine. Now you need offsets. And you can start throwing tomatoes.

struct.h
Code:
#if !ASSEMBLY
    #define structfield(type, asmtype, name) type name;
    #define beginstruct(name) typedef struct name {
    #define endstruct(name) } name;
#else
    #define structfield(type, asmtype, name) name asmtype
    #define beginstruct(name) .struct name
    #define endstruct(name) .endstruct
#endif


beginstruct(MyFoo)
    structfield(char, .byte, i)
    structfield(int, .word, p)
endstruct(MyFoo)



If you include it into the C file, everthing will be fine. For assembler, convert this header into intermediate ".i" file using the following line:

Code:
cc65 struct.h -DASSEMBLY -E


Which will output:

Code:
.struct MyFoo
i .byte
p .word
.endstruct

Author:  Banshaku [ Fri Nov 16, 2018 7:30 pm ]
Post subject:  Re: Accessing C struct members from Assembly?

There is no automated way, unfortunately (except for maybe the hack above but I don't know if there is any drawback to do so :lol:).

What I do is I have a file that contains the definition, again, for the asm side and I keep them in sync when updated. If you don't have many structure to share it may not be a big issue. An example of what I used:

C side:
Code:
typedef struct {
   const unsigned char* frameCount;
   const unsigned char* const *frameList;
} animInfo_t;

typedef struct {
   unsigned char index;           // index of the frame to be shown
   unsigned char count;           // current count for next frame
   unsigned char maxCount;        // how long is the frame
   const unsigned char* current;  // the current frame to be shown
} frameInfo_t;

// player's specific information
typedef struct {
   int x;                     // location inside stage. May need negative, not sure yet.
   int y;                      // vertical location, now 16 bits for checking bound outside screen
   unsigned char direction;       // which direction facing, left or right
   unsigned char priority;         // if shown priority is front or background
   unsigned char outOfBound;      // if went out of bound in a direction (up/down/left/right) based on the limit of the map
   unsigned char state;          // state of actor (for player, this means animState)
   unsigned char subState;        // state that modify current state (ex: using weapon while doing somethings)
   unsigned char previousState;   // previous states
   unsigned char health;         // tentative: value for health
   unsigned char invicibleTimer;  // flag & counter for invincible state (> 0, in that state)
   unsigned char weapon;          // which weapon was selected
   frameInfo_t frame;
   animInfo_t anim;
} player_t;


Asm side (started to convert recently, maybe issue in it)
Code:
;
; Info regarding animation for the currently selected anim
;
.struct FrameInfo
    index       .byte
    count       .byte
    maxCount    .byte
    current     .word
.endstruct

;
; animation info
;
.struct AnimInfo
    frameCount  .word
    frameList   .word
.endstruct

;
; Player information definition
;
.struct Player
    posX        .word
    posY        .word
    direction   .byte
    priority    .byte
    outOfBound  .byte
    state       .byte
    subState    .byte
    previousState .byte
    health      .byte
    invicibleTimer .byte
    weapon      .byte
    frame       .tag FrameInfo
    anim        .tag AnimInfo
.endstruct


Something like that.

Then in asm you just use the struct, like expected:

Code:

lda _gplayer + Player::state


Author:  yaros [ Fri Nov 16, 2018 8:30 pm ]
Post subject:  Re: Accessing C struct members from Assembly?

Banshaku wrote:
There is no automated way, unfortunately (except for maybe the hack above but I don't know if there is any drawback to do so :lol:).


I don't think there are any dwarbacks, except it is just ugly. What would be better, is instead of using C89 macroses, is to use powerfuul ca65 macros system and generate C89 header file. It will be a little cleaner, but I was coming from the assumption that C89 is the primary where ca65 is secondary, so generation was coming from C header files.

Author:  gauauu [ Fri Nov 16, 2018 8:34 pm ]
Post subject:  Re: Accessing C struct members from Assembly?

Yeah, the C has more type information than what would be in the assembly (signed vs unsigned, whether it's an int vs a pointer), so my intention was to go that direction.

Author:  gauauu [ Fri Nov 16, 2018 8:36 pm ]
Post subject:  Re: Accessing C struct members from Assembly?

Either way, thanks for the suggestions. I appreciate the input.

Author:  yaros [ Fri Nov 16, 2018 8:42 pm ]
Post subject:  Re: Accessing C struct members from Assembly?

gauauu wrote:
Yeah, the C has more type information than what would be in the assembly (signed vs unsigned, whether it's an int vs a pointer), so my intention was to go that direction.


True, but you can create ca65 macroses like. Just because ca65 macroses are WAY more powerful, teples even tried (or did) create assembler using them.

Code:
    STRUCT "MyFoo"
      FIELD "char", x
      FIELD "unsigned int", y
   ENDSTRUCT


That will generate either C struct or ASM struct depending on the defined symbol.

Code:
.macro FIELD type, name
   .ifdef ASSEMBLER
      .if .match({type}, "char")
         name .byte
      .elseif .match({type}, "int") .or .match({type}, "unsigned int") .or .match({type}, "uint16_t")  .or .match({type}, "int16_t")
         name .word
      .endif
   .else
   .endif
.endmacro

Page 1 of 1 All times are UTC - 7 hours
Powered by phpBB® Forum Software © phpBB Group
http://www.phpbb.com/