modelmachine/docs/implementation.md at main · cmc-python/modelmachine

Данная реализация модельной машины состоит из классов, разбитых на файлы-модули:

  • memory.py - память; делится на два класса: регистровая и оперативная; оперативная делится на little-endian и big-endian
  • cell.py - целочисленная арифметика с фиксированным числом двоичных знаков
  • alu.py - арифметико-логическое устройство, работает с четко специализированными регистрами: R1, R2, S, FLAGS и PC.
  • cu.py - контролирующее устройство, выполняющее считывание команд из памяти и запускающее необходимые методы в арифметико-логическом устройстве
  • io.py - устройство ввода-вывода
  • cpu.py - финальное объединение составляющих устройств в единое целое
  • asm.py - ассемблер для машины с модификацией адресов

Здесь дано поверхностное описание модулей. За более подробным обращайтесь к документации конкретных модулей и их исходным кодам.

memory.py

AbstractMemory - класс абстрактной памяти, предоставляющий интерфейс для надежной связи частей компьютера. Основные методы: fetch и put, которые принимают на вход адрес в памяти и количество битов, с которыми нужно работать, количество должно быть кратно размеру ячейки (слова). Строго рекомендуется их использовать везде.

RandomAccessMemory - класс, реализующий память прямого доступа. При инициализации указывается размер машинного слова и количество этих слов. Если is_protected=True, то при попытке считывания из неинициализированной ячейки будет выброшено исключение, иначе, метод fetch вернет нуль.

RegisterMemory - класс, реализующий регистровую память. Метод add_register добавляет регистр определенного размера или проверяет, что уже добавленный регистр имеет правильный размер.

cell.py

Класс Cell реализует целочисленную арифметику фиксированной длины. Поддерживаемые операторы: +, -, *, /, %, ==. Плюс методы signed и unsigned. Округление при делении производится в сторону нуля.

alu.py

Арифметико-логическое устройство работает с четко специализированными регистрами:

  • R1, R2, S для арифметических операций.
  • FLAGS для хранения флагов состояния.
  • PC только для пересылки туда адреса из регистра R1 при условных переходах.

Схема работы:

  • Арифметические команды: add, sub, smul, sdiv, umul, udiv, sdivmod, udivmod. За исключением команд divmod арифметические команды работают следующим образом: S := R1 op R2. Плюс в зависимости от результата выставляется регистр FLAGS - комбинация флагов CF, OF, SF и ZF.
  • add и sub - сложение и вычитание соответсвенно.
  • smul и sdiv - знаковое умножение и деление соответсвенно.
  • umul и udiv - беззнаковое умножение и деление соответсвенно.
  • sdivmod и udivmod - знаковое и беззнаковое соответственно деление с остатком. S := R1 / R2; R1 := R1 % R2.
  • Команда пересылки move: S := R1.
  • Команды безусловного перехода jump и условного перехода cond_jump работают по схеме PC := R1, режим работы cond_jump зависит от того, какие дополнительные аргументы будут переданы.
  • Команда останова halt просто выставляет флаг остановки HALT в регистре флагов

cu.py

Управляющее устройство.

AbstractControlUnit

Обычно управляющее устройство работает по схеме:

  1. fetch_and_decode - загрузка и расшифровка очередной команды. Содержимое ячейки оперативной памяти с адресом записанным в регистре PC загружается в регистр RI, затем из него извлекается код операции и адреса операндов, затем счетчик PC увеличивается на длину только что считанной команды.
  2. load - данные по только что считанным адресам загружаются в регистры процессора R1 и R2
  3. execute - в зависимости от кода операции в арифметико-логическом устройстве запускается та или иная схема вычислений.
  4. write_back - результат вычислений записывается куда полагается (например, по одному из адресов считанных в начале).

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

  • step - сделать один шаг, описанный алгоритмом выше.
  • get_status - вернуть статус процессора (выполняется/остановлен). Остановка производится командой останова halt.
  • run - выполнять один шаг за другим, пока процессор не будет остановлен.

Далее, наследники AbstractControlUnit определяют первые 4 метода.

io.py

Устройство ввода-вывода.

  • При инициализации устанавливается адрес с которого нужно загружать программы пользователя.
  • Метод load_source загружает последовательность шеснадцатиричных слов по указанному адресу.
  • Метод load_data загружает данные (полученные из строки чисел) по данным адресам.
  • Методы get_int и put_int работают с содержимым одного слова. Размер слова устанавливается при инициализации.

cpu.py

Финальная сборка всех составных устройств в единое целое.

  • Поддерживается доступ к составным устройствам. Например, доступ к устройству ввода/вывода можно получить через cpu.io_unit, к регистрам через cpu.registers и так далее.
  • load_program - загрузка программы, конфигурации и данных в оперативную память.
  • print_result - печать результата работы программы.
  • run_file - загрузка, исполнение и печать результата.

Поддерживаемые архитектуры

Как добавить новую архитектуру?

  1. Выписать все команды устройстройства и их коды.
  2. Добавить их в таблицу в README и описание там же.
  3. Добавить новый класс устройства управления по аналогии с существующим.
  4. Добавить новый класс CPU использующий это устройство управления, добавить этот класс в список CPU_LIST в файле cpu.py.
  5. Добавить тесты для обоих этих классов в файлы tests/test_cu.py и tests/test_cpu.py.
  6. Добавить примеры в папку samples.
  7. Прислать pull request.