Pointer problem with simple preprocessor define

M

Martin

Hi all,

I have a simple memory mapped interface, and I would like to write
through this values to two registers and then read them back. The
following code example works fine:

volatile int *reg1 = (int *) 0x80000000;
volatile int *reg2 = (int *) 0x80000004;

*reg1 = 12; *reg2 = 23;
printf("reg1 = %i\n", *reg1);
printf("reg2 = %i\n", *reg2);

Instead of "hardcoding" the addresses, I would like the address to be
put together from a base address and an offset. Using some preprocessor
statements, I wanna have some defines

#define WriteReg(BaseAddress, RegOffset, Data) \
*((volatile int *)((char*)BaseAddress + RegOffset)) = (unsigned
int)(Data)

#define ReadReg(BaseAddress, RegOffset, Data) \
(unsigned int)(Data) = *((volatile int *)((char*)BaseAddress +
RegOffset))


WriteReg((int *) 0x80000000, 0, 12);
WriteReg((int *) 0x80000000, 4, 23);

ReadReg((int *) 0x80000000, 4, res);
printf("Reg2 = %i\n", res);

ReadReg((int *) 0x80000000, 0, res);
printf("Reg1 = %i\n", res);

The output is now in either case 1073804536, instead of 12 and 23,
respectively. So I assume I must have done something horrible wrong with
the pointers, anyone a comment how I can properly build up this address
with a define statement?

Thanks a lot, Martin
 
E

Eric Sosman

Hi all,

I have a simple memory mapped interface, and I would like to write
through this values to two registers and then read them back. The
following code example works fine:

volatile int *reg1 = (int *) 0x80000000;
volatile int *reg2 = (int *) 0x80000004;

*reg1 = 12; *reg2 = 23;
printf("reg1 = %i\n", *reg1);
printf("reg2 = %i\n", *reg2);

Instead of "hardcoding" the addresses, I would like the address to be
put together from a base address and an offset. Using some preprocessor
statements, I wanna have some defines

#define WriteReg(BaseAddress, RegOffset, Data) \
*((volatile int *)((char*)BaseAddress + RegOffset)) = (unsigned int)(Data)

#define ReadReg(BaseAddress, RegOffset, Data) \
(unsigned int)(Data) = *((volatile int *)((char*)BaseAddress + RegOffset))


WriteReg((int *) 0x80000000, 0, 12);
WriteReg((int *) 0x80000000, 4, 23);

ReadReg((int *) 0x80000000, 4, res);
printf("Reg2 = %i\n", res);

ReadReg((int *) 0x80000000, 0, res);
printf("Reg1 = %i\n", res);

The output is now in either case 1073804536, instead of 12 and 23,
respectively. So I assume I must have done something horrible wrong with
the pointers, anyone a comment how I can properly build up this address
with a define statement?

What is `res'? Perhaps more importantly, where is `res' given
a value?

(If this hint doesn't lead you to a solution, please post a
*short* and *complete* program that demonstrates your difficulty.)
 
M

Martin

#define ReadReg(BaseAddress, RegOffset, Data) \
What is `res'? Perhaps more importantly, where is `res' given
a value?

"res" if of type unsigned integer. It is passed in ReadReg and should
then be asigned the value at a certain offset from a baseaddress.
 
M

Martin

Why are you mixing so many casts?

I agree, its too many. I used the char so that I can use bytes for the
offset rather than 4-byte intervals. But probably it is easier to leave
the char cast out.
 
E

Eric Sosman

"res" if of type unsigned integer. It is passed in ReadReg and should
then be asigned the value at a certain offset from a baseaddress.

Ahem:

MORE IMPORTANTLY, WHERE IS `res' GIVEN A VALUE?

In the fragment you posted, `res' (whatever it may be) is never
assigned to, so anything you see when it's printed, no matter how
surprising it might be, is unsurprising.

Code, Martin. Show actual code, not incomplete snippets. If
you show fragments and only fragments, my diagnosis can only be that
your error is on line forty-two.
 
S

Seebs

#define WriteReg(BaseAddress, RegOffset, Data) \
*((volatile int *)((char*)BaseAddress + RegOffset)) = (unsigned
int)(Data)
Ah-hah!

WriteReg((int *) 0x80000000, 0, 12);

You are getting

((char *) (int *) BaseAddress + RegOffset)

and I think you do not want the inner (int *). These macros are doing
enough (int *) already.

-s
 
I

Ian Collins

On 10/27/10 02:14 PM, Martin wrote:

Please don't snip attributions, it's rude.
I agree, its too many. I used the char so that I can use bytes for the
offset rather than 4-byte intervals. But probably it is easier to leave
the char cast out.

You are also casting to unsigned int before assigning to *(int*) as well
as casting the parameter in the macro invocation!

Just treat the address and offset as numbers and cast the sum.
 
P

Peter Nilsson

Martin said:
I have a simple memory mapped interface, and I would like
to write through this values to two registers and then read
them back. The following code example works fine:

volatile int *reg1 = (int *) 0x80000000;
volatile int *reg2 = (int *) 0x80000004;

*reg1 = 12; *reg2 = 23;
printf("reg1 = %i\n", *reg1);
printf("reg2 = %i\n", *reg2);

You can do...

#define REG1 (* (volatile int *) 0x80000000)
REG1 = 12;
printf("reg1 = %i\n", REG1);
Instead of "hardcoding" the addresses, I would like the
address to be put together from a base address and an
offset. Using some preprocessor statements, I wanna have
some defines

#define WriteReg(BaseAddress, RegOffset, Data) \
*((volatile int *)((char*)BaseAddress + RegOffset))
= (unsigned int)(Data)

#define ReadReg(BaseAddress, RegOffset, Data) \
(unsigned int)(Data) = *((volatile int *)((char*)
BaseAddress + RegOffset))

WriteReg((int *) 0x80000000, 0, 12);
WriteReg((int *) 0x80000000, 4, 23);

This is still hardcoding!
ReadReg((int *) 0x80000000, 4, res);
printf("Reg2 = %i\n", res);

ReadReg((int *) 0x80000000, 0, res);
printf("Reg1 = %i\n", res);

The output is now in either case 1073804536, instead of 12
and 23, respectively. So I assume I must have done something
horrible wrong with the pointers, anyone a comment how I can
properly build up this address with a define statement?

#define ReadReg(base, offset) \
( * (const volatile int *) ((base) + (offset)) )

#define WriteReg(base, offset, data) \
( * (volatile int *) ((base) + (offset)) = (data) )

WriteReg(0x80000000, 0, 12);
WriteReg(0x80000000, 4, 23);
printf("Reg1 = %d\n", ReadReg(0x80000000, 0));
printf("Reg2 = %d\n", ReadReg(0x80000000, 4));
 
E

Eric Sosman

Ahem:

MORE IMPORTANTLY, WHERE IS `res' GIVEN A VALUE?

In the fragment you posted, `res' (whatever it may be) is never
assigned to, so anything you see when it's printed, no matter how
surprising it might be, is unsurprising.

Confession: I read over-hastily, and overlooked part of the code
you posted. Nonetheless, by happenstance, it happens that my question
still stands: Your code does not assign anything to `res'. In fact,
your code should not compile at all unless you are operating your
compiler in a non-C "dialect" or "patois" mode. If so, when you post
the complete code please identify the compiler and whatever options
you are using with it.
 
T

Tim Rentsch

Martin said:
Hi all,

I have a simple memory mapped interface, and I would like to write
through this values to two registers and then read them back. The
following code example works fine:

volatile int *reg1 = (int *) 0x80000000;
volatile int *reg2 = (int *) 0x80000004;

*reg1 = 12; *reg2 = 23;
printf("reg1 = %i\n", *reg1);
printf("reg2 = %i\n", *reg2);

Instead of "hardcoding" the addresses, I would like the address to be
put together from a base address and an offset. Using some
preprocessor statements, I wanna have some defines

#define WriteReg(BaseAddress, RegOffset, Data) \
*((volatile int *)((char*)BaseAddress + RegOffset)) = (unsigned
int)(Data)

#define ReadReg(BaseAddress, RegOffset, Data) \
(unsigned int)(Data) = *((volatile int *)((char*)BaseAddress +
RegOffset))


WriteReg((int *) 0x80000000, 0, 12);
WriteReg((int *) 0x80000000, 4, 23);

ReadReg((int *) 0x80000000, 4, res);
printf("Reg2 = %i\n", res);

ReadReg((int *) 0x80000000, 0, res);
printf("Reg1 = %i\n", res);

The output is now in either case 1073804536, instead of 12 and 23,
respectively. So I assume I must have done something horrible wrong
with the pointers, anyone a comment how I can properly build up this
address with a define statement?

Using macros in this way, with a base address and offsets,
seems horribly error prone. You could just let C do the
work, thus:

volatile int *mm_registers = (void*) 0x80000000;

mm_registers[0] = 12;
mm_registers[1] = 23;

printf( "Register 2 = %i\n", mm_registers[1] );
printf( "Register 1 = %i\n", mm_registers[0] );

(assuming of course you're working with 4-byte int's).

Also, guessing you are using gcc, use one of these

gcc -ansi -pedantic
gcc -std=c99 -pedantic

to avoid getting gcc's extensions.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top