as stated in the title, I am implementing a processor emulator in C# and I have a problem with understanding, that is, with the paging logic when retrieving an instruction from memory.
Namely, I have a 64-bit address space and in the program I specify an arbitrary number of addresses, for example 1000, where each address is 64 bits long.My first problem in understanding is, when I create an instruction and when I add it to the memory, should I add it to a physical or a virtual address?
That 64-bit address is divided, with the last 12 bits being reserved for the offset and the remaining bits being used for paging tables. For example, let's say we have 4 paging levels, the first 9 bits are used for the level 4 paging table (we'll start from the bottom), the next 9 bits are used for the level 3 paging table, and so on until we reach the level 1 paging table that has access to the physical address.
What I don't understand here is what is obtained by going through these paging tables and how do we get the physical address from the virtual address, do I have to specify both physical and virtual addresses at the beginning of the program and map one to the other? I don't understand that going through those pagination tables, what am I even getting with that?
What is the situation with the program counter, does it contain a physical address or that virtual address? In order for the instruction to be fetched and executed, do I need to have a physical or virtual address in the program counter? If someone is willing to explain the principle of paging to me with an example, how would I understand how I should realize the implementation?
For example, let me have a 64-bit address: 0x0001234FFFFADE09, how can I find it on a concrete example. Is E09 an offset and the rest a paging table? And then what is 000 for the level 4 paging table and so I move on? But then how do I get a physical address based on this address, did I specify that physical address somewhere, I'm quite confused.