Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

represent memory in c

I am trying to write an Instruction Set Simulator in C to simulate a machine running ARM. I need to be able to represent 4GB memory efficiently and after some digging have come to the solution of creating an array of 1024 pointers each pointing to a block of 4MB which is dynamically allocated at its first use

#define MEMSIZE 1024    //1024 * 2Mb = 4Gb
#define PAGESIZE 4194304    //4 Mb
#define PAGEEXP 22      //2^PAGEEXP = PAGESIZE

uint32_t* mem[MEMSIZE];

My question is how do I access a certain address of memory?

What I have tried is breaking the address into index and offset as below but this seems to only return 0 for both index and offset. (memAdd is the address I am trying to access)

memIdx = memAdd >> PAGEEXP;
memOfs = memAdd & PAGESIZE;

the functions I use to read/write once I have the address are below:

void memWrite(uint32_t idx, uint32_t ofs, uint32_t val)
{
    if(mem[idx] == 0)
        mem[idx] = malloc(PAGESIZE);
    *(mem[idx] + ofs) = *(mem[idx] + ofs) & val;
}

uint32_t memRead(uint32_t idx, uint32_t ofs)
{
    if(mem[idx] == 0)
        return 0;
    else
        return *(mem[idx] + ofs);
}

these seem right in my head however I am still not 100% comfortable with pointers so this may be wrong.

Sorry if this has already been discussed somewhere but I couldnt find anything relevent to what I need ( my keywords are pretty broad)

like image 394
Scott Avatar asked Jun 07 '26 19:06

Scott


1 Answers

Start out looking at it logically instead of at the bit level.

You have pages of 4,194,304 bytes each.

Arithmetically, then, to turn a linear address into a (page, offset) pair, you divide by 4,194,304 to get the page number, and take the remainder to get the offset into the page.

page = address / PAGESIZE;
offset = address % PAGESIZE;

Since you want to do this efficiently and these are powers of 2, you can replace division by PAGESIZE with right-shift by the base-2 logarithm of PAGESIZE, which is 22:

page = address >> PAGEEXP;

So that part of your code is correct. However, what you want to do to get the offset is to mask out all but the bits you just shifted out of the page number. To do that, you have to AND with PAGESIZE - 1.

offset = address & (PAGESIZE - 1);

This is because in binary, what you're starting with is a number that looks like this (where p is a page number bit and o is an offset bit):

address = ppppppppppoooooooooooooooooooooo

You want to get the page number and the offset number by themselves. You clearly want to shift right by 22 bits to get the page number:

page = addresss >> 22 = 0000000000000000000000pppppppppp

But if you AND with the pagesize (00000000010000000000000000000000 in binary), you'll only have one at most one 1-bit in the answer, and it will just tell you if the page number is odd or even. Not useful.

What you want to AND with is instead one bit less than that, which is binary 00000000001111111111111111111111, thus:

  ppppppppppoooooooooooooooooooooo 
& 00000000001111111111111111111111
-----------------------------------
= 0000000000oooooooooooooooooooooo

which is how you get the offset.

This is a general rule: if N is an integer power of 2, then division by N is the same as right-shifting by log(N)/log(2), and the remainder of such a division is given by ANDing with (N-1).

like image 132
Mark Reed Avatar answered Jun 10 '26 08:06

Mark Reed



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!