coderx.ru - образовательный портал
тема нашего урока: виртуальный процессор
1.
процессор должен понимать определенный набор команд
Код:
//придумаем свои опкоды для инструкций
#define ERROR 0
#define MOVE_regreg 1
#define MOVE_regdata 2
#define ADD_regreg 3
#define ADD_regdata 4
#define SUB_regreg 5
#define SUB_regdata 6
#define JMP_ofset 7
#define JMP_reg 8
#define JNZ_ofset 9
#define JNZ_reg 10
Код:
//и для регистров
#define regA 0
#define regB 1
#define regC 2
#define regD 3
#define regE 4
#define regIp 6
2.
придумаем массив функций
Код:
PVOID flist[100]={0};//сюда будем складывать функции, соотвественно опкодам
работать с ним будем примерно так:
- вытягиевает наш процессор из памяти байт, он равен 7
- получаем адрес функции из массива p = flist[7]
- вызываем эту функцию p();
- вытягиевает наш процессор из памяти байт, он равен 3
- получаем адрес функции из массива p = flist[3]
- вызываем эту функцию p();
- вытягиевает наш процессор из памяти байт, он равен 5
- получаем адрес функции из массива p = flist[5]
- вызываем эту функцию p();
- -------
3.
у процессора должны быть регистры(как минимум), будет он выглядеть примерно так:
Код:
//придумаем виртуальный процессор + вспомогательный функционал
class processor
{
public:
//регистры
DWORD reg_A;
DWORD reg_B;
DWORD reg_C;
DWORD reg_D;
DWORD reg_E;
//регистр флагов
DWORD zFlag;
//указатель на инструкцию
DWORD * Ip;
bool execute() //выполнить 1 инструкцию
{
if (*Ip>=100)//навешиваем проверочки, типа не быдлокодеры нифига
{
printf("error1, кривая инструкция\n");
return false;
};
bool (*p)(processor*) = (bool (__cdecl *)(processor *))(flist[*Ip]);//достаем адресок функции из массива
if (p == 0)//проверяем
{
printf("error2, неизвесная инструкция\n");
return false;
};
if( p(this)==false) //вызываем функцию
{
printf("error3, внутренняя ошибка\n");
return false;
};
return true;
};
void run(DWORD * code)
{
Ip = code;
while (execute());//выполнять до любой ошибки
};
void printreg()
{
printf("%p A=%x B=%x C=%x D=%x E=%x\n",Ip,reg_A,reg_B,reg_C,reg_D,reg_E);
};
} vcpu;
4.
пишем код который будет выполнять виртуальные инструкции.
например мы хотим инструкцию которая обнуляет регистр A
Код:
bool fx_zero_regA(processor * p)
{
//переводим указатель Ip на следующую виртуальную инструкцию
p->Ip+=1; //если размер нашей инструкции 5 байт, значит делаем +5
//обнуляем регистр А
p->regA=0;
return true;
};
//по такому же принципу пишем все нужные нам функции
bool f0_ERROR(processor * p);
bool f1_MOVE_regreg(processor * p);
bool f2_MOVE_regdata(processor * p);
bool f3_ADD_regreg(processor * p);
.............
.......
...
5.
теперь начинается веселая часть
Код:
/*
пишем софтину для нашего ололо процессора,
вычисляет площадь прямоугольника
входящие данные в регистрах A и B
результат в регистре С
*/
DWORD testprogram[]=
{
MOVE_regdata, regA, 100, //длинна
MOVE_regdata, regB, 50, //ширина
MOVE_regdata, regC, 0, //результат
MOVE_regreg, regD, regB, //"временная переменная"
//пичалька, проц не поддерживает умножение, тогда нужно сложение в цикле
MOVE_regreg, regE, regIp, //запоминаем куда нам вернутся
ADD_regreg, regC,regA, //добавляем длинну к результату
SUB_regdata, regD,1,
JNZ_reg, regE, //прыгаем "куда запоминали"
ERROR
};
6.
обнуляем все что можно
Код:
memset( &vcpu,0,sizeof(vcpu));
заполняем массив функций
Код:
flist[0]=f0_ERROR; //расставляем функции согласно их "опкодам"
flist[1]=f1_MOVE_regreg;
flist[2]=f2_MOVE_regdata;
......
...
..
командуем виртуальному процессору выполнять виртуальную программу
Код:
vcpu.run(testprogram);
7.
исходник
virtualCPU.zip
8.
приятных кошмариков