views:

78

answers:

4

I'm doing programming of a softcore processor, Nios II from Altera, below is the code in one of the tutorial, I manage to get the code working by testing it on the hardware (DE2 board), however, I could not understand the code.

#define Switches (volatile char *) 0x0003000
#define LEDs (char *) 0x0003010
void main()
{ while (1)
*LEDs = *Switches;
}

What I know about #define is that, it is either used to define a constant, or a macro, but

  1. why in the above code, there are casting like, (char *) 0x0003010, in #define?
  2. why the 2 constants, Switches and LEDs act like a variable instead of a constant?

Thanks in advance !

+4  A: 

It appears that Switches and LEDs represent the memory-mapping to the actual input (in the case of Switches) and output (in the case of LEDs).

So your answers include:

  1. The byte for the input switches is memory-mapped to address 0x0003000. In order to access that as a byte, you need to tell the compiler that whatever is at address 0x0003000 is a char (in fact, you tell it that the value at that address is a volatile char, so that the compiler doesn't optimize away the fact that the value at that address may change at any time).

  2. They are constants, but they are constant pointers. That is to say, the address is constant, but the values contained at those addresses are not constant.

What happens is that every clock cycle (or so), whatever is read from memory address 0x0003000 is then written to address 0x0003010. This gives the illusion that the switches instantly toggle the LEDs.

Mark Rushakoff
+3  A: 

In C, macros are simple substitutions.

Every time the compiler sees LEDs in your code it will replace it with (char *) 0x0003010.

So your code is effectively the same as this:

void main()
{
    while (1)
        *(char *) 0x0003010 = *(volatile char *) 0x0003000;
}
Artelius
The preprocessor, Not the compiler.
dig
@dig: In C, the preprocessing phases are part of the compilation process, and it is correct to say that the compiler performs those tasks, even though some implementations might use a separate program to perform the preprocessing phases.
James McNellis
@James: but it is clearer in this context to say "preprocessor" where you mean "preprocessor".
dmckee
@james: it's the same process running both modules. but preprocessor and the compiler are not the same thing. the preprocessor runs prior to the compiler, and "sets the ground" for the compiler to do his job.saying that preprocessor and the compiler are the same thing is like saying that the linker and the compiler are the same thing.
dig
preprocessing is part of the first step of a compiler (for many compiler and in some implementation it could be totally embedded, even though likely it does not happen often); your assertion is like saying that you should split the "compiler" into all steps it do as conceptualy separated actions (so you should add at least also assembly and linking steps); why saying "to compile" I can intend "C to assembly (if this step is done, conceptually is always done...), assembly to machine codes, packing machine codes into object format, linking the obj ...", and not the first preproc step?
ShinTakezou
"is part" should be "could be part"... not all compilers of all languages embed a preprocessor or call an external one...
ShinTakezou
A: 

Without the type casting at the #defines, they wouldn't be treated as char* and volatile char*. What is at *Switches is copied into *LEDs.

vpit3833
+4  A: 

1) why in the above code, there are casting like, (char *) 0x0003010, in #define?

Preprocessor macros are textual replacements. So the code comes out as

while (1) {
  *(char *) 0x0003010 = *(volatile char *) 0x0003000
}

which repeated assigns the contents of the input (switch) mapped at 0x3000 to the output (led) mapped at 0x3010.

2) why the 2 constants, Switches and LEDs act like a variable instead of a constant?

Note that those are pointer. So they always point to the same place (which happens to be a couple of memory mapped IO pins or something similar), but there is no guarantee the the contents of those constant locations are constant, and the * appearing before each preprocessor symbol is the pointer de-reference operator.

dmckee