Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
АРХІТЕКТУРА КОМП.doc
Скачиваний:
49
Добавлен:
28.10.2018
Размер:
453.12 Кб
Скачать

Модель процессора

Модель процессора должна определять алгоритм выборки команд из памяти и алгоритмы выполнения каждой операции. Алгоритм выборки команд — это основной цикл интерпретатора, который представляет собой следующую последовательность действий:

  1. Выбрать из M2[PC] очередные два байта;

  2. Определить КОП;

  3. Если требуется, выбрать еще 2, 4 или 6 байт;

  4. Сформировать полную команду во внутреннем регистре процессора

  5. Выполнить команду;

  6. Изменить PC;

  7. Перейти на 1;

Во-первых, отметим, что в алгоритме регистр счетчика команды изменяется после выполнения команды. Таким образом, в нем сохраняется адрес обрабатываемой команды. Это более удобно, так как в этом случае при аварийной ситуации PC показывает на аварийную команду.

Во-вторых, пункт 3 в данной схеме не совсем ясен: как процессор «узнает», сколько еще байт выбирать из памяти? Это можно однозначно определить по коду операции. Например, процессор выбирает из памяти два байта 08 0А. Первый байт соответствует коду операции условного перехода JL. Следовательно, второй байт — это номер регистра. Значит, процессору осталось выбрать еще 2 байта смещения. Другой пример: выбраны байты 2А 00. Первый байт является кодом операции LDWI, следовательно, второй — номер регистра $W. Это значит, что процессору осталось выбрать еще 4 байта — непосредственный операнд. Если процессор выбрал два байта 43 04, то первый байт соответствует коду операции NOT, а второй — это номер регистра. В этом случае ничего дополнительно выбирать не нужно.

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

Таким образом, для каждой команды где-то должна храниться ее размер. Кроме того, интерпретатор должен «собирать» полную команду, выбирая из памяти оставшиеся байты. В реальных компьютерах команда собирается во внутреннем регистре процессора, недоступном программисту. Этот регистр в интерпретаторе можно промоделировать восьмибайтным массивом:

uByte rc[8]; // регистр команд

Байт rc[0] содержит код операции для основных команд. Для команд из дополнительного множества код операции находится в rc[1].

Все составляющие модели процессора удобно собрать в один модуль. Более того, удобно представить модель компьютера в виде класса, включающего все структуры данных (регистры, память, стек) и все необходимые алгоритмы в виде методов. Очевидно, что один из методов реализует основной цикл процессора, другой — начальные установки всех регистров при старте.

Теперь подробнее остановимся на шаге 5 — выполнение команды. В интерпретаторе AMS выполнение команд было инкапсулировано в функции run() в единственном операторе-переключателе. Такое решение было приемлемым, поскольку архитектура AMS проста, и объем интерпретатора весьма мал. Однако для VM такая реализация представляется не самым лучшим вариантом по следующим причинам:

  • количество операций достаточно большое, поэтому оператор-переключатель будет очень длинным; кроме того, одним переключателем не обойтись, так как код операции может быть либо 1 байт (основное множество операций), либо 2 байта (дополнительное множество операций);

  • команды имеют разный размер, поэтому необходимо где-то хранить длину команды; эта величина должна быть известна во время выполнения основного цикла процессора;

  • команды разного формата, поэтому прежде, чем выполнять команду, требуется «разобраться» с ее аргументами;

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

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

Однако при отсутствии оператора-переключателя возникает проблема вызова необходимой функции: по имени функцию вызывать невозможно, поскольку все имена разные. Однако в С++ можно вызывать функцию по указателю, и это позволяет нам применить хорошо известный типичный прием, который состоит в следующем:

  • имена функций при старте заносятся в массив указателей (на функцию);

  • индексом в массиве указателей является код операции.

В этом же массиве удобно хранить и размер соответствующей команды. Поэтому представляется весьма удобным определить для каждой команды структуру из двух полей:

  • имя реализующей функции;

  • длина команды.

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