PDA

Просмотр полной версии : чтиво на ночь


destructor
12.11.2011, 02:09
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.
исходник 2455

8.
приятных кошмариков

MyGarant.net
12.11.2011, 02:12
Меньше знаешь - крепче спишь. Не буду читать.

destructor
12.11.2011, 02:19
1. вызывать нужные функции разумнее через case, вместо извращений с массивом, но мне так надо

2. если увеличить количество инструкций, получится достаточно умная штучка

Hint
12.11.2011, 02:26
Вроде бы на втором курсе в институте писали свой виртуальный процессор и ассемблер, компилирующий исходные коды в "бинарные" файлы для исполнения. Процессор должен был поддерживать заданный набор инструкций (в том числе условные переходы), иметь несколько регистров, работать со стеком. Ассемблер поддерживал метки, переменные нескольких типов. А потом под свой "процессор" (у всех были те или иные различия как в наборе инструкций, так и в базовых вещах, например количестве поддерживаемых операндов) писали демонстрационные примеры (например, вычисление факториала). Было интересно :)
А ближе к последним курсам уже проектировали реальные счетные устройства из элементарных логических блоков и триггеров: на входы подаешь операнды в двоичном коде, код операции (сложение, умножение и т. д.), а на выходах через несколько тактов получаешь результат. Взглянуть бы сейчас на эти схемы (может где на жестком валяется проект в ладе или протеусе).

destructor
12.11.2011, 02:45
Ассемблер поддерживал метки, переменные нескольких типов. чтото жостка они вас:D

Добавлено через 5 минут
Hint, гдето на "радиотехнике" учился?

Hint
12.11.2011, 02:57
чтото жостка они вас:D

Вообще в самый раз :) Это ведь не на неделю задание. По-моему даже на целый семестр. И по сути работа состоит из независимых "модулей", которые можно разрабатывать отдельно (парсинг текстовых файлов, класс работы с хеш-таблицами и т. д.). Лично мне было интересно этим заниматься, хотя большинство конечно передирало работы прошлых лет. Во-первых, практика программирования, во-вторых, знакомство с устройством компьютера на всех уровнях (чем отличается двухпроходный ассемблер от однопроходного и т. д.).
Вот дальше было сложнее, когда пришлось разрабатывать язык более высокого уровня =) Различные циклы (for, while), блоки инструкций, условные операторы и т. д. Правда это уже писалось не с нуля, а с использование лексичесих и синтаксических анализаторов (lex, yacc). Есть что вспомнить :)
http://ru.wikipedia.org/wiki/Yacc
http://ru.wikipedia.org/wiki/Lex
Кстати, эти инструменты могут пригодиться и в реальных проектах (более приземленных). Например, для парсинга серверных скриптов lineage 2 (именно они и используются в l2server). Регулярками ведь те же npcdata и itemdata не разберешь.

Добавлено через 2 минуты
Hint, гдето на "радиотехнике" учился?
Официально называется "Вычислительные машины, комплексы, системы и сети" (специальность 230101).

Xa4ik
12.11.2011, 07:30
class proccessorнапоминает проФФеССор (http://www.google.com.ua/search?q=%D0%BF%D1%80%D0%BE%D1%84%D1%84%D0%B5%D1%8 1%D0%BE%D1%80+%D1%8F%D0%BD%D1%83%D0%BA%D0%BE%D0%B2 %D0%B8%D1%87&hl=ru&source=hp&gs_sm=e&gs_upl=1362l7166l0l9065l12l12l1l0l0l0l244l1896l0.8 .3l11l0&oq=%D0%BF%D1%80%D0%BE%D1%84%D1%84%D0%B5%D1%81%D1%8 1%D0%BE%D1%80+&aq=0s&aqi=g-s4g-sv2g-v1&aql=)
bool (*p)(proccessor*) = (bool (__cdecl *)(proccessor *))(flist[*Ip])спаяный с логических елементов, етот кусок будет понятен для мозга...

destructor
12.11.2011, 11:09
class proccessorпоправлю:D

спаяный с логических елементов, етот кусок будет понятен для мозга...знаю что ужос, сюда можно не смотреть, там дальше каммент идет.

mira
18.11.2011, 14:53
Тут самое главное прально продумать архитекуру опкодов и написать какоенеть подобие компилятора. (ох ненавижу я весь этот парсинг и проверку синтаксиса)