Простой процессор
Простой процессор – модель 8-разрядного процессора, снабженного 256-байтным банком памяти. Основное назначение простого процессора – работа учебным стендом для наглядного объяснения принципов функционирования вычислительной техники, архитектуры процессоров, ассемблирования, выборки и исполнения команд. Неосновное назначение – причинение боли и страдания студентам-бездельникам и тем, кто наивно полагает, что в XXI веке программирование в машинных кодах больше никем и нигде не используется (спойлер: используется). Простой процессор – это предельно упрощенная и лишенная возможности микропрограммирования и ввода-вывода базовая ЭВМ.
Простой процессор имеет 4 регистра общего назначения (РОНа) – R0, R1, R2 и R3, регистр флагов RF и регистр-указатель команд RC. Простой процессор может непосредственно адресовать 256 байтов памяти, в которой размещаются команды и данные. Простой процессор оперирует 8-разрядными целыми числами со знаком (для представления отрицательных чисел используется дополнительный код). Числа могут быть записаны в десятичной системе счисления, шестнадцатеричной (с префиксом 0x, например, 0xAB) или двоичной (с префиксом 0b, например, 0b10101011).
Три малдших бита в регистре RF являются арифметическими флагами, остальные биты не используются. Бит Z (самый младший бит) устанавливается в 1 в случае, если результат последней арифметической команды равен 0, в противном случае бит Z сбрасывается в 0. Бит S (бит с порядковым номером 1) устанавливается в 1 в случае, если результат последней арифметической команды имеет в старшем бите единицу (то есть может рассматриваться как отрицательное число), в противном случае бит S сбрасывается в 0. Бит C (бит с порядковым номером 2) устанавливается в 1 в случае, если результат последней арифметической команды не поместился в разрядную сетку, и за её пределы был выполнен перенос, в противном случае бит C сбрасывается в 0. Проверить значения флагов в регистре RF можно с помощью команд условного перехода.
Регистр-указатель команд RC содержит адрес следующей исполняемой команды. Команды перехода фактически заносят в этот регистр адрес ячейки памяти, откуда нужно продолжить выборку команд. После "включения" простого процессора все регистры содержат нули и выполнение программы начинается с адреса 0.
Простой ассемблер для простого процессора
Простой ассемблер позволяет перейти от программирования в машинных кодах к символической записи команд, то есть, например, вместо записи команды в машинном коде 18 fe (или в двоичном представлении 00011000 11111110) записать её мнемоникой r2 <- @0xfe. Каждая команда может быть снабжена меткой (идентификатором, после которого стоит двоеточие, например, BEGIN:). Метка должна располагаться перед командой ассемблера в той же строке, что и команда.
Правильно:
BEGIN: r2 <- @0xfe ; читаем текущее значение
Неправильно:
BEGIN:
r2 <- @0xfe ; читаем текущее значение
Простой ассемблер не различает верхний и нижний регистр символов, поэтому 0xFE и 0xfe – одно и то же число, r0 и R0 – один и тот же регистр, LOOP: и loop: – одна и та же метка.
Простым ассемблером поддерживаются однострочные комментарии, они начинаются с символа ; и продолжаются до конца строки. Простой ассемблер игнорирует пробельные символы и комментарии.
Система команд простого процессора
| Мнемоника | Двоичное представление | Команда |
|---|---|---|
| Rdd <- Rss | 0000ddss | Пересылка данных из регистра в регистр |
| Rdd <- @aaaaaaaa | 0001dd?? aaaaaaaa | Пересылка данных из памяти в регистр |
| @aaaaaaaa <- Rss | 0010??ss aaaaaaaa | Пересылка данных из регистра в память |
| Rdd <- nnnnnnnn | 0011dd?? nnnnnnnn | Запись в регистр константы |
| Rdd <- Rdd + Rss | 0100ddss | Сложение |
| Rdd <- Rdd − Rss | 0101ddss | Вычитание |
| Rdd <- Rdd * Rss | 0110ddss | Умножение |
| Rdd <- Rdd / Rss | 0111ddss | Деление (беззнаковое) |
| RF <- Rdd ~ Rss | 1000ddss | Сравнение |
| RC <- @aaaaaaaa (C) | 1001???? aaaaaaaa | Переход, если перенос |
| RC <- @aaaaaaaa (S) | 1010???? aaaaaaaa | Переход, если знак |
| RC <- @aaaaaaaa (Z) | 1011???? aaaaaaaa | Переход, если ноль |
| RC <- @aaaaaaaa | 1100???? aaaaaaaa | Безусловный переход |
| Rdd <- ? | 1101dd?? | Запись случайного числа в регистр |
| Rdd <- Rss++ | 1110ddss | Инкремент |
Команды простого процессора могут быть поделены на несколько категорий:
- команды пересылки данных
- арифметические команды
- команды передачи управления
Арифметические операции с данными возможны только в том случае, если данные находятся в регистрах. Все арифметические команды действуют по одному принципу: данные берутся из регистра-назначения (первый операнд, в команде обозначаемый как Rdd), затем – из регистра-источника (второй операнд, в командах обозначаемый как Rss), над ними производится действие, определяемое кодом операции, после чего результат записывается в регистр назначения и в регистре флагов устанавливаются соответствующие флаги. Команда сравнения, фактически работающая как команда вычитания, отличается от последней тем, что результат не сохраняется, но флаги в регистре флагов устанавливаются. Необходимо также отметить, что команда деления в простом процессоре работает с числами без знака.
Команды пересылки данных позволяют загрузить данные из памяти в РОНы для обработки и записать результаты из РОНов обратно в память. Команда инкремента Rdd <- Rss++, формально относящаяся к командам пересылки данных, похожа на копирование данных из регистра в регистр, но позволяет при этом записать в регистр назначения увеличенное на единицу значение регистра-источника.
В простом процессоре нет отдельной команды NOP (No OPeration), однако в таком качестве можно использовать запись из регистра в тот же регистр, например, r0 <- r0. Отдельной команды для останова процессора (HLT, HaLT) также не предусмотрено, для этого можно применять команду безусловного перехода на тот же адрес:
HLT: rc <- @HLT ; стоп