gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

Coding > Assigning values to system addresses through #define

#79492 - Natso - Fri Apr 14, 2006 12:42 am

Code:
#define rcnt   ((volatile u16 *)0x00000134);

static u16 mplayinit(){

   rcnt=0;

   return 0;

}


Ok, I feel really stupid cause I can't figure this out but I'll feel stupider if I stay up all night and don't ask, so...
I'm trying to assign a new value to "rcnt". Coincidintally this is one of the addresses involved in multiplayer connections, but I don't think that will make a difference here.
As you can see, rcnt is supposed to be a variable with a specific location(in my document it says it is located at "134h" and so I derived the location for the #define) however I have inexperience doing this and... well I have to clue as to what to do :D
_________________
I'm a bomb technitian. If you see me running, try to keep up ;)

#79496 - keldon - Fri Apr 14, 2006 1:02 am

(a) that is the wrong address for RCNT
(b)
Code:
#define   REG_BASE   0x04000000
#define REG_RCNT      *(vu16*)(REG_BASE + 0x134)   // SIO Mode Select/General Purpose Data


vu16 is of type u16 volatile. This is defined in gba_sio.h.

#79497 - Cearn - Fri Apr 14, 2006 1:06 am

Natso wrote:
Code:
#define rcnt   ((volatile u16 *)0x00000134);

This is a pointer to put a value into a pointer, you need to dereference it. Also, all IO registers are in the 0400:0000h range, 0x134 is just an offset in that range

Code:

// 0x04000134 is an address
// ((volatile u16*)0x04000134) is a pointer
// *((volatile u16*)0x04000134) is a dereferenced pointer
#define REG_RCNT   *((volatile u16*)0x04000134)
REG_RCNT= 0;

Incidentally, there are a great number of sites with the full range of REG_x defines and all sorts of other neat stuff. You could save yourself a lot of typing by just grabbing some of that code.

EDIT: because I lose all ability to spell after 2am


Last edited by Cearn on Fri Apr 14, 2006 1:16 am; edited 1 time in total

#79500 - Natso - Fri Apr 14, 2006 1:13 am

yeah, but I like to know exactly what the code is doing & stuff like that. I will go and try that code now. thanks for the help btw
_________________
I'm a bomb technitian. If you see me running, try to keep up ;)

#79502 - Natso - Fri Apr 14, 2006 1:29 am

#define rcnt *((volatile u16*)0x04000134)
rcnt= 0;


Ok for this, it says that there is a syntax error before the =. I assume this means that rcnt is the problem. Obviosly the code didn't work. Any clues?
_________________
I'm a bomb technitian. If you see me running, try to keep up ;)

#79504 - Cearn - Fri Apr 14, 2006 1:37 am

Natso wrote:

Code:

#define rcnt *((volatile u16*)0x04000134)
rcnt= 0;
Ok for this, it says that there is a syntax error before the =. I assume this means that rcnt is the problem. Obviously the code didn't work. Any clues?


The assignment should be done inside a function.

If you're new to C, you might want to take a look at the tutorials gathered here

#79507 - Natso - Fri Apr 14, 2006 1:45 am

Lol. the 2nd line was inside a perfectly legal function. Is there any other reason this line would not work?
_________________
I'm a bomb technitian. If you see me running, try to keep up ;)

#79511 - Cearn - Fri Apr 14, 2006 1:56 am

Natso wrote:
Lol. the 2nd line was inside a perfectly legal function. Is there any other reason this line would not work?
Uhmmm, no?

Oh wait, are you sure you have a typedef or define for 'u16'?

Code:
typedef short u16;

Other than that, I can't thing of anything. Just copy pasted to be sure, but it runs fine for me.

Try this:
Code:

typedef short u16;

#define REG_RCNT (*(volatile u16*)0x04000134)

int main()
{
   REG_RCNT=0;

   return 0;
}

Doesn't do anything useful, but at the very least it should compile. If not, post the 'exact' error(s) you're getting.

#79516 - Cearn - Fri Apr 14, 2006 2:35 am

NOTE: Crossposted. Twice. >_<

Natso wrote:
#define rcnt *((volatile u16*)0x04000134)
rcnt= 0;

Ok for this, it says that there is a syntax error before the =. I assume this means that rcnt is the problem. Obviosly the code didn't work. Any clues?


Me wrote:
Code:
// 0x04000134 is an address
// ((volatile u16*)0x04000134) is a pointer
// *((volatile u16*)0x04000134) is a dereferenced pointer
#define REG_RCNT   *((volatile u16*)0x04000134)
REG_RCNT= 0;

:P

The whole thing with asterixes and pointers is just part of C syntax. The number 0400:0134 (easier to read notation for 0x04000134) is a memory address, indicating a certain range of bits in GBA memory. But an address in itself doesn't mean very much to C itself, for that you need pointers, indicated by a unary asterix. Strictly speaking, pointers are variables that contain an address. The ' type' of a pointer tells the compiler how it's supposed to deal with that address. For example
Code:
// typedefs for u16 and u32 to shorten the code
typedef unsigned short u16;
typedef unsigned int u32;

u16 *p16= (u16*)0x06000000;
u13 *p32= (u32*)0x06000000;

p16 and p32 are both pointers to the address 0600:0000. However, p16 uses it in 16bit chunks (2 bytes at a time), while p32 uses it in 32bit chunks (4bytes). Both are completely legal. To make use of the contents of the address the pointer points to, you 'dereference' it by using either another asterix in front of it.
Code:
*p16= 0x1234;     // dereferences p16; writes 0x1234 into address 0600:0000
*p32= 0x12345678; // dereferences p32; writes 0x12345678 into address 0600:0000

The reason you need the extra asterix is because simply assigning a value to the pointer changes the pointer itself, not the thing it points to. Or at least it would if it were legal to do that without an explicit cast, but it's the thought that counts.
Code:
*p16= 0x1234;     // dereferences p16; writes 0x1234 into address 0600:0000
p16= 0x1234; // p16 now points to address 0x1234

Arrays have a lot in common. In fact, they can often be interchanged.
Code:
*p16= 0x1234;     // dereferences p16; writes 0x1234 into address 0600:0000 (into 0600:0000 and 0600:0001, really)
*p32= 0x12345678; // dereferences p32; writes 0x12345678 into address 0600:0000 (:0000, :0001, :0002 and :0003)
// equivalent to:
p16[0]= 0x1234;
p32[0]= 0x12345678;

// writes 0x1234 into the first halfword [i]after[/i] 0600:0000. I.e., 0600:0002 (2 bytes because a halfword is 2 bytes long)
p16[1]= 0x1234;
// writes 0x12345678 into the first word [i]after[/i] 0600:0000. I.e., 0600:0004 (4 bytes because a word is 4 bytes long)
p32[1]= 0x12345678;

// pointer/array equivalency encore: does the same as above
// parentheses are required because of operator precedence
*(p16+1)= 0x1234;
*(p32+1)= 0x12345678;

The number between brackets is an offset from the starting point of the pointer or array, in units of the pointer/array type. That's why the actual addresses of p16[1] and p32[1] is different. Think about it for a while and you'll see that this is a sensible thing to do. By the way, you can find the address using '&'.
Code:
&p16[0]  // gives 0600:0000
&p16[1]  // gives 0600:0002
&p32[1]  // gives 0600:0004

In these cases I've use an actual variable for the pointers, but that's not really necessary. The pointer cast itself is enough.
Code:
*(u16*)0x06000000= 0x1234; // take a guess
*(u32*)0x06000000= 0x12345678;

Of course, magic numbers are considered evil, so we cover them up with #defines
Code:
#define MEM_VRAM 0x06000000
#define vid_mem ((u16*)MEM_VRAM)

vid_mem[0]= 0x1234;  // 0x1234 into 0600:0000
vid_mem[1]= 0x5678;  // 0x5678 into 0600:0002

Again, the outer pair of parentheses are required due to operator precedence.
Code:
#define MEM_VRAM 0x06000000
#define vid_mem (u16*)MEM_VRAM

// this is (u16*)0x06000000[1], which is parsed as (u16*)(0x06000000[1])
// numbers aren't arrays or pointers, so this fails
vid_mem[1]= 0x5678;



Back to the original #define
Code:
#define rcnt *((volatile u16*)0x04000134)

rcnt= 0;

0x04000134 is an address.
(volatile u16*)0x04000134 casts it to a volatile u16 pointer. The volatile is necessary because the contents of this address can be modified by hardware, and you need to tell the compiler that.
*(volatile u16*)0x04000134 dereferences the pointer so that it works as a variable. A halfword variable, because the pointer's type is u16.

Right. I hope this makes any kind of sense; I've slept about 4 hours of the last 66, so I'm starting to have trouble judging. I'll go over it again tomorrow if necessary.

#79532 - Natso - Fri Apr 14, 2006 4:11 am

AAAAAAAAAAAGH I'm going totally crazy.
My problem with my code was a ; in the #define(Yeah now i feel terribly stupid to have wasted hours on a ; ).

Regardless you have tought me much in that post, and I should be able to retype my code in a working manner. Thanks a bunch bunch bunch for you help in letting me sleep tonight(I wouldn't have slept a wink). In the meantime you need to break your 66hour spell and get some sleep too.

- Zach
_________________
I'm a bomb technitian. If you see me running, try to keep up ;)