Virtual machine puppetry - Part 1

 



Have you ever wonder how you can be a part of those people who understand what is going on in the virtual machine workers? If so, I will guide you to a little-tiny project that can run a simple program from loading it to a local memory to decoding and run instructions. 


Let's get started! :)


Down the rabbit hole

on behalf of reading this article, you have to work on your knowledge about how CPU's work. You will need a very-well (fine) understanding of low-level stuff. Whatever, Talk is cheap, Show me the code!


Here is a basic structure of normal-32bit instruction format:


 * Instruction format

 * header: 2 bits

 * data: 32 bits


 * header format:

 * 0 -> positive integer

 * 1 -> primitive instruction

 * 2 -> negative integer

 * 3 -> undefined


The Primitive Instruction also known as Executor. whenever we find this instruction we must do something with data.


Let's create a class (for god sake):

class StackVM

{

public:

StackVM();

void run();

void loadProgram(std::vector<i32> prog);


private:

i32 pc = 100; // program counter

i32 sp = 0; // stack pointer

std::vector<i32> memory;

i32 typ = 0;

i32 dat = 0;

i32 running = 1;


i32 getType(i32 instruction);

i32 getData(i32 instruction);

void fetch();

void decode();

void execute();

void doPrimitive();

};


Variable Descriptions:

i32 pc: program counter is a small memory space, and its function can be seen as the line number. In the conceptual model of the virtual machine, the decoder works by changing the value of this counter to select the next instruction to be executed.

i32 sp: Simply holds the base address of our memory stack.

std::vector<i32> memory: This will hold are program memory to be executed.

i32 typ: Holds the type of instruction from instruction header.

i32 dat: Holds the actual data of the instruction.

i32 running: Just a flag that indicates whether we have to run continuously or not.


Functions Descriptions:

i32 getType(i32 instruction): reads and decode requested instruction for finding the TYPE

i32 getData(i32 instruction): reads and decode requested instruction for finding the DATA


Before we get into other functions, its nice for you to know what is the basic operation of CPU?

All types of CPU's whatever its Intel/Amd or something else, they all have one thing in common, ONE THING! and its not just a infinite loop of 3 operations known as:

  • Fetch: In simple words, gets the instruction from memory and adds +1 to program counter
  • Decode: As the name is clear, it will decode the instruction for the data, holding the next instruction to run for Fetch
  • Execute: Executes the requested instruction based on decoded operations, calling internal CPU functions to the job
The image below will open your vision more:



Thats enough for now, As the above I said we will need these operations of course, so there is:

void fetch();

void decode();

void execute();


And the last but not least:

void doPrimitive(): The manager of how we decide to do with the each of instruction



That's it for Part 1, will continue for the next (Part 2).



Comments