Question

I am having trouble aligning memory for DMA transfer on the Cell processor. I need the last 4 bits of an address to be 0.

I have 4 arrays of unsigned int where each element must be aligned in memory so that its (hex) adress ends with a zero.

E.g.

int main()
{
    size_t i;

    static unsigned int a[2] __attribute__ ((aligned (16)));
    static unsigned int b[2] __attribute__ ((aligned (16)));
    static unsigned int c[2] __attribute__ ((aligned (16)));
    static unsigned int d[2] __attribute__ ((aligned (16)));

    for (i = 0; i < 2; ++i) {
        printf("a[%u] = %p\n", &a[i]);
        printf("b[%u] = %p\n", &b[i]);
        printf("c[%u] = %p\n", &c[i]);
        printf("d[%u] = %p\n", &d[i]);
    }

    return 0;
}

Output:

a[0] = 0x10010b60
b[0] = 0x10010b50
c[0] = 0x10010b40
d[0] = 0x10010b30
a[1] = 0x10010b64
b[1] = 0x10010b54
c[1] = 0x10010b44
d[1] = 0x10010b34

The problem here is that the 2nd element of each array doesn't seem to be 16-bit aligned (their address' end with a 4).

I need the addresses to look like this:

a[0] = 0xXXXXXXX0
b[0] = 0xXXXXXXX0
c[0] = 0xXXXXXXX0
d[0] = 0xXXXXXXX0
a[1] = 0xXXXXXXX0
b[1] = 0xXXXXXXX0
c[1] = 0xXXXXXXX0
d[1] = 0xXXXXXXX0
Était-ce utile?

La solution

The alignment attribute specifies the alignment of variables or structure fields, not single array elements. See Specifying Attributes of Variables and Common Variable Attributes for details.

If you always want to align two integers together, you can define a structure

struct dma_transfer {
    unsigned int e0 __attribute__ ((aligned (16)));
    unsigned int e1 __attribute__ ((aligned (16)));
};

This aligns the elements on 16 byte boundaries.

int main(int argc, char **argv)
{
    static struct dma_transfer a;
    static unsigned int b[2];

    printf("a.e0 = %p\n", &a.e0);
    printf("a.e1 = %p\n", &a.e1);
    printf("b[0] = %p\n", &b[0]);
    printf("b[1] = %p\n", &b[1]);

    return 0;
}

gives, e.g.

a.e0 = 0x601060
a.e1 = 0x601070
b[0] = 0x601080
b[1] = 0x601084

But this means also, that you have holes between the two integer values. On a 32 bit system, you will have

| int 4 bytes | hole 12 bytes |
| int 4 bytes | hole 12 bytes |

Autres conseils

If arr is an array of 32-bit elements, and the address of arr[0] is 0xXXXXXXX0, then the address of arr[1] will necessarily be 0xXXXXXXX4.

For your purpose, you need to use arrays of 16-byte elements:

typedef struct
{
    unsigned int x;
    unsigned char reserved[16-sizeof(unsigned int)];
}
element_t;

static element_t a[2] __attribute__ ((aligned (16)));
static element_t b[2] __attribute__ ((aligned (16)));
static element_t c[2] __attribute__ ((aligned (16)));
static element_t d[2] __attribute__ ((aligned (16)));

Alternatively, you can simply refrain from using arrays altogether.

Instead, use plain variables, and tell the compiler to align them to 16 bytes:

static unsigned int a0 __attribute__ ((aligned (16)));
static unsigned int a1 __attribute__ ((aligned (16)));
static unsigned int b0 __attribute__ ((aligned (16)));
static unsigned int b1 __attribute__ ((aligned (16)));
static unsigned int c0 __attribute__ ((aligned (16)));
static unsigned int c1 __attribute__ ((aligned (16)));
static unsigned int d0 __attribute__ ((aligned (16)));
static unsigned int d1 __attribute__ ((aligned (16)));

I really don't think you can do that ... You're trying to get the compiler to inject extra padding for alignment purposes "inside" an unsigned int. But there's no space to do that, all of the bits in an unsigned int are already used for the integer itself.

I think the solution is to wrap the integer in a structure, since then you can use the __attribute__(()) magic on the structure, and make an array of that.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top