tags:

views:

177

answers:

5

BACKGROUND:
I'm writing a single level cache simulator in C for a homework assignment, and I've been given code that I must work from. In our discussions of the cache, we were told that the way a small cache can hold large addresses is by splitting the large address into the position in the cache and an identifying tag. That is, if you had an 8 slot cache but wanted to store something with address larger than 8, you take the 3 (because 2^3=8) rightmost bits and put the data in that position; so if you had address 22 for example, binary 10110, you would take those 3 rightmost bits 110, which is decimal 5, and put it in slot 5 of the cache. You would also store in this position the tag, which is the remaining bits 10.

One function, cache_load, takes a single argument, and integer pointer. So effectively, I'm being given this int* addr which is an actual address and points to some value. In order to store this value in the cache, I need to split the addr. However, the compiler doesn't like when I try to work with the pointer directly. So, for example, I try to get the position by doing:
npos=addr%num_slots

The compiler gets angry and gives me errors. I tried casting to an int, but this actually got me the value that the pointer was pointing to, not the numerical address itself. Any help is appreciated, thanks!

[edit]

int load(int * addr) { 
  int value = (use_memory ? (*addr) : 0);
  intptr_t taddr=(intptr_t) addr;
  int npos=taddr % blocks;
  int ntag=taddr / blocks;
  printf("addr is %p, taddr is %p, npos is %d and ntag is %d\n",addr,taddr,npos,ntag);

When addr is passed in, it's actual address is 58, and it points to a value of 88. The output I'm getting from that printf is:

addr is 58, taddr is 58, npos is 0 and ntag is 11

So it seems taddr is getting 58 (when printed with %p, still shows 88 when printed with %d), but npos and ntag are showing up as 0 and 11 (as though the mathematical operations are being run with 88) instead of 2 and 7 as I'd like.

The code is used like this:

void load_words (int n, int words[]) {
  int i;
  for (i=0; i<n; i++) {
    load( (int *) (words[i] * 4));
    cache_print();
  }
}
A: 
int *pointer;
uint32_t address = (uint32_t) pointer;

Except of course, you have no guarantee that an int* fits in an uint32_t, so you need to pick the right types for your platform.

Andrew McGregor
How can I go about picking the right type for the platform? I'm getting a "`uint32_t' undeclared (first use in this function)" which I assume means it's not the right type.
Airjoe
try "uint32" instead.
mingos
@Airjoe, make sure you're including `<stdint.h>`.
dreamlax
+3  A: 

You should use something like

int *pointer;
intptr_t address=(intptr_t) pointer;

and this is mainly just a correction on @Andrew's post

So your function should become

(oops forgot this was homework. I'll roll back this question in a while. Can't straight give you the answer :) )

Earlz
Updated my code as described, still am getting the following output:addr is 58, taddr is 88, npos is 0 and ntag is 11When I expect npos to be 2 and ntag to be 7.
Airjoe
@Air if you go to http://www.easycalculation.com/hex-converter.php and put in `58` it will be 88. The values are actually the same, they are just being displayed in a different base.
Earlz
I'm quite sure this is the most standard way of converting a pointer type to an integer type. +1.
dreamlax
+2  A: 

The C99 standard says that a conversion from a pointer type to an integer type or vice versa is implementation defined behaviour (6.3.2.3.5 and 6.3.2.3.6), except where one uses intptr_t or uintptr_t defined in <stdint.h>, however 7.18.1.4 says these two types are not compulsory and an implementation does not need to provide them.

dreamlax
A: 

Decimal 88 is 0x58 (hex 58). When you use the %p specifier with printf, the hex representation is printed out. So both addr and taddr are decimal 88, and your calculations are correct.

Ray
Right, Earlz explained this above. So the 58 is not what I thought it was, and my calculations are still wrong. (I thought 58 was the actual address in memory, and I was wondering why it was such a small number...). I need to split the actual memory address, which I guess I can't find at all now.
Airjoe
The specification for the `%p` format specifier says: "The argument shall be a pointer to void. The value of the pointer is converted to a sequence of printing characters, in an implementation-defined manner." It doesn't have to print in hexadecimal, it could print in octal or decimal, but hexadecimal is probably the most common representation.
dreamlax
Something here doesn't add up. Where does the parameter addr come from? What are you passing into the function?I suspect you're doing this:int * value = 88;load(value);Instead, you should be doing the following:int value = 58;load(That will pass the address of the variable value into your function.
Ray
A: 

One important thing not already mentioned here. When you print a pointer with the %p specifier, then you should cast the argument:

printf("addr is %p\n", (void *)addr);

%p expects a pointer to void, and a specifier/argument mismatch for printf is undefined behavior.

Secure