commit 4c63632d609e04c810222271475b238d75edd010 Author: LeterZP Date: Tue Mar 24 21:51:05 2026 +0300 Squashed 'OPD/OPDLab4/' content from commit 7f018ee git-subtree-dir: OPD/OPDLab4 git-subtree-split: 7f018ee58ee43b36fdf015d79189b15dcf836687 diff --git a/guide.md b/guide.md new file mode 100644 index 0000000..31d0867 --- /dev/null +++ b/guide.md @@ -0,0 +1,461 @@ +# Гайд по 4 лабораторной работе по ОПД + +--- + +## Содержание + +- [Введение](#Введение) + +- [Стек](#Стек) + + - [Основы](#Основные-понятия) + + - [Реализация в БЭВМ](#Базовая-ЭВМ) + +- [Подпрограммы](#Подпрограммы) + +- [Команды](#Команды) + + - [Адресация относительно стека](#Косвенная-относительная-адресация-со-смещением-относительно-SP) + + - [POP](#POP) + + - [POPF](#POPF) + + - [PUSH](#PUSH) + + - [PUSHF](#PUSHF) + + - [SWAP](#SWAP) + + - [CALL](#CALL) + + - [RET](#RET) + + - [IRET](#IRET) + +- [Источники](#Источники) + +--- + +## Введение + +Здесь вкратце описана инфрмация, необходимая для защиты 4 лабы по ОПД. + +## Стек + +### Основные понятия + +> **Стек** - это структура данных, рабтающая по принципу LIFO (Last-In-First-Out), или "последним зашёл, первым вышел". + +Стек можно представить как стопку книг. Книги можно ставить друг на друга только сверху, и чтобы достать какую-то определённую книгу, придётся сначала снять все остальные. + +В основном для взаимодействия со стеком используются два действия: положить на стек и снять со стека. + +### Базовая ЭВМ + +*Всё, что описано ниже, верно для актуальной версии эиулятора базовой ЭВМ (bcomp-ng v1.45.09).* + +Для взаимодействия со стеком используется ряд команд, среди которых [POP](#POP), [POPF](#POPF), [PUSH](#PUSH), [PUSHF](#PUSHF) и [SWAP](#SWAP). Все они подробно рассмотрены ниже. + +Сам стек распологается в последних ячейках памяти БЭВМ (точнее, он заполняется, начиная с последней ячейки памяти). Для управления стеком используется 11-разрядный регистр указателя стека (Stack Pointer - SP), который показывает последнюю заполненную ячейку стека. По умолчанию значение SP равно 0, что означает, что стек пуст (*также это можно рассматривать и с другой стороны: указатель стека ставится на одну ячейку ниже той, в которую будет записано следующее его значение, и тогда 0 в SP будет образовываться из-за переполнения, а точнее добавления 1 к номеру последней ячейки памяти, то есть 7FF*). + +## Подпрограммы + +*Всё, что описано ниже, верно для актуальной версии эиулятора базовой ЭВМ (bcomp-ng v1.45.09).* + +В актуальной версии БЭВМ подпрограммы являются некой мини-программой, которую удобно применять в случае, если какие-либо однотипные действия в основной программе выполняются по несколько раз. + +Для вызова подпрограммы и возврата из неё предусмотрен ряд команд, среди которых [CALL](#CALL), [RET](#RET), [IRET](#IRET). + +В БЭВМ использование подпрограмм сильно переплетено с использованием стека. В основном стек используется для временного хранения каких-либо данных, необходимых для выполнения подпрограммы. В частности, в стек записываются адрес возварщения подпрограммы (то есть место, где программа должна будет продолжить выполнение после выполнения подпрограммы), аргументы подпрограммы и результаты выполнения подпрограммы. + +Для передачи аргументов для подпрограммы необходимо перед вызовом подпрограммы загрузить в стек необходимо количество параметров, а в подпрограмме выполнить с этими аргументами необходимые действия. При этом в подпрограмме в данном случае для взаимодействия со стеком используется специальный [режим адресации относительно стека]() (впрочем, данный режим адресации можно использовать не только в подпрограмме). После этого результат выполнения подпрограммы может быть записан в те же ячейки стека, где передавались аргументы, и завершить работу подпрограммы. Также стоит отметить, что передавать аргументы для подпрограммы можно не только через стек, но и используя регистры общего назначения (к сожалению, в БЭВМ он только один, и это AC). + +## Команды + + + +### Косвенная относительная адресация со смещением относительно SP + +В третем ниббле имеет код C (в двоичной системе соответственно 1100), то есть имеет вид XCXX. + +В ассемблере БЭВМ обозначается как &M или (SP+M), никакой разницы между данными обозначениями нет. + +Как и любая другая косвенная адресация, имеет максимально 255 полученных через смещение ячеек, из которых 128 отрицательных (и не имеют практического применения из-за особенностей стека). Таким образом, максимальное количество ячеек, к которым можно получить доступ с помощью данной адресации - это 127. + +#### Цикл выборки адреса + +- 1 такт: **SXT_CR(0..7) -> BR** + + - По фронту происходит дополнение знака в АЛУ *(то есть значения битов 15..8 становятся равными биту 7, где отсчет битов ведётся справа налево начиная с 0)*. + - По спаду результат записывается в буферный регистр. + +- 2 такт: **BR + SP -> DR** + + - По фронту начение буферного регистра суммируется со значением указателя стека в АЛУ. + - По спаду результат записывается в регистр данных. + +#### Цикл выборки операнда + +- 1 такт: **DR -> AR** + + - По фронту пускает значение из регистра данных через АЛУ. + - По спаду записывает это значение в адресный регистр. + +- 2 такт: **MEM(AR) -> DR** + + - По фронту находит ячейку в памяти по адресу. + - По спаду записывает значение этой ячейки в регистр данных. + + + +### POP + +Код: 0800. + +Выгружает верхнее значение стека в аккумулятор. + +Безадресная команда. + +#### Цикл выборки операнда + +- 1 такт: **SP -> AR** + + - По фронту пускает значение регистра через АЛУ. + + - По спаду записывает его в адрсный регистр. + +- 2 такт: **MEM(AR) -> DR** + + - По фронту находит по адресу ячейку. + + - По спаду записывает значение этой ячейки в регистр данных. + +#### Цикл исполнения + +- 1 такт: **DR -> AC** + + - По фронту пускает значение регистра данных через АЛУ. + + - По спаду запишет его в аккумулятор. + +- 2 такт: **SP + 1 -> SP** + + - По фронту пустит значение указателя стека в АЛУ и прибавит 1. + + - По спаду запишет полученное значение в указатель стека. + +*После выполнения поставит флаги в соответствии с выгруженным значением, при этом не изменив флаг переноса и обнулив флаг переполнения*. + +Цикл выборки адреса выполняться не будет, так как команда безадресная. + + + +### POPF + +Код: 0900. + +Выгружает верхнее значение стека в регистр состояния. + +Безадресная команда. + +#### Цикл выборки операнда + +- 1 такт: **SP -> AR** + + - По фронту пускает значение регистра через АЛУ. + - По спаду записывает его в адрсный регистр. + +- 2 такт: **MEM(AR) -> DR** + + - По фронту находит по адресу ячейку. + - По спаду записывает значение этой ячейки в регистр данных. + +#### Цикл исполнения + +- 1 такт: **DR -> PS** + + - По фронту пустит значение регистра данных в АЛУ. + + - По спаду запишет это значение в регистр состояния. + +- 2 такт: **MEM(AR) -> DR** + + - По фронту находит по адресу ячейку. + - По спаду записывает значение этой ячейки в регистр данных. + +*Флаги, соответственно, возьмутся из регистра состояния.* + +Цикл выборки адреса выполняться не будет, так как команда безадресная. + + + +### PUSH + +Код: 0C00. + +Загружает значение аккумулятора на вершину стека. + +Безадресная команда. + +#### Цикл исполнения + +- 1 такт: **AC -> DR** + - По фронту пустит значение аккумулятора через АЛУ. + + - По спаду запишет его в регистр данных. +- 2 такт: **~0 + SP -> SP, AR** + - По фронту прибавит в АЛУ к значению указателя стека ~0 (то есть -1). + + - По спаду запишет это значение в указатель стека и адресный регистр. +- 3 такт: **DR -> MEM(AR)** + - По фронту найдёт ячейку по адресу. + + - По спаду запишет значение регистра данных в эту ячейку. + +*Не меняет флаги*. + +Цикл выборки адреса выполняться не будет, так как команда безадресная. + +Цикл выборки операнда выполняться не будет, так как нужное нам значение уже записано в аккумуляторе. + + + +### PUSHF + +Код: 0D00. + +Загружает значение регистра состояния на вершину стека. + +Безадресная команда. + +#### Цикл исполнения + +- 1 такт: **PS -> DR** + + - По фронту пустит значение регистра состояния через АЛУ. + + - По спаду запишет это значение в регистр данных. + +- 2 такт: **~0 + SP -> SP, AR** + + - По фронту прибавит в АЛУ к значению указателя стека ~0 (то есть -1). + - По спаду запишет это значение в указатель стека и адресный регистр. + +- 3 такт: **DR -> MEM(AR)** + + - По фронту найдёт ячейку по адресу. + - По спаду запишет в эту ячейку значение регистра данных. + +*Не меняет флаги*. + +Цикл выборки адреса выполняться не будет, так как команда безадресная. + +Цикл выборки операнда выполняться не будет, так как нужное нам значение уже записано в регистре состояния. + + + +### SWAP + +Код: 0E00. + +Меняет местами значение аккумулятора и верхнее значение стека. + +Безадресная команда. + +#### Цикл исполнения + +- 1 такт: **SP -> AR** + + - По фронту пустит значение указателя стека через АЛУ. + + - По спаду запишет это значение в адресный регистр. + +- 2 такт: **MEM(AR) -> DR** + + - По фронту найдёт ячейку по адресу. + + - По спаду запишет значение этой ячейки в регистр данных. + +- 3 такт: **DR -> BR** + + - По фронту пустит значение регистра данных через АЛУ. + + - По спаду запишет это значение в буферный регистр. + +- 4 такт: **AC -> DR** + + - По фронту пустит значение аккумулятора через АЛУ. + + - По спаду запишет это значение в регистр данных. + +- 5 такт: **BR -> AC; DR -> MEM(AR)** + + - По фронту пустит значение буферного регистра через АЛУ, а также найдет ячейку по адресу. + + - По спаду запишет значение из АЛУ в аккумулятор, а также запишет значение регистра данных в ячейку памяти. + +*Ставит флаги по загруженному значению, не меняя флаг переноса и обнуляя флаг переполнения.* + +Цикл выборки адреса выполняться не будет, так как команда безадресная. + +Цикл выборки операнда выполняться не будет, так как нужное нам значение уже записано в аккумуляторе. + + + +### CALL + +Код: DXXX. + +Вызывает подпрограмму по заданному адресу. + +Адресная команда. + +*Цикл выборки адреса и цикл выборки операнда зависят от типа адресации.* + +#### Цикл исполнения + +- 1 такт: **DR -> BR** + + - По фронту пустит значение регистра данных через АЛУ. + + - По спаду запишет это значение в буферный регистр. + +- 2 такт: **IP -> DR** + + - По фронту пустит значение счетчика команд через АЛУ. + + - По спаду запишет это значение в регистр данных. + +- 3 такт: **BR -> IP** + + - По фронту пустит значение буферного регистра через АЛУ. + + - По спаду запишет это значение в счетчик команд. + +- 4 такт: **~0 + SP -> SP, AR** + + - По фронту прибавит в АЛУ к значению указателя стека ~0 (то есть -1). + + - По спаду запишет это значение в указатель стека и адресный регистр. + +- 5 такт: **DR -> MEM(AR)** + + - По фронту найдёт ячейку по адресу. + + - По спаду запишет в эту ячейку значение регистра данных. + +*Не меняет флаги*. + + + +### RET + +Код: 0A00. + +Прекращает выполнение подпрограммы. + +Безадресная команда. + +#### Цикл выборки операнда + +- 1 такт: **SP -> AR** + + - По фронту пустит значение указателя стека через АЛУ. + + - По спаду запишет это значение в адресный регистр. + +- 2 такт: **MEM(AR) -> DR** + + - По фронту найдёт ячейку по адресу. + + - По спаду запишет значение этой ячейки в регистр данных. + +#### Цикл исполнения + +- 1 такт: **DR -> IP** + + - По фронту пустит значение регистра данных в АЛУ. + + - По спаду запишет это значение в счетчик команд. + +- 2 такт: **SP + 1 -> SP** + + - По фронту пустит значение указателя стека в АЛУ и прибавит 1. + + - По спаду запишет полученное значение в указатель стека. + +*Не меняет флаги.* + +Цикл выборки адреса выполняться не будет, так как команда безадресная. + + + +### IRET + +Код: 0B00. + +Записывает верхнее значение стека в регистр состояния, а после прекращает выполнение подпрограммы. + +Безадресная команда. + +#### Цикл выборки операнда + +- 1 такт: **SP -> AR** + + - По фронту пустит значение указателя стека через АЛУ. + + - По спаду запишет это значение в адресный регистр. + +- 2 такт: **MEM(AR) -> DR** + + - По фронту найдёт ячейку по адресу. + + - По спаду запишет значение этой ячейки в регистр данных. + +#### Цикл исполнения + +- 1 такт: **DR -> PS** + + - По фронту пустит значение регистра данных в АЛУ. + + - По спаду запишет это значение в регистр состояния. + +- 2 такт: **SP + 1 -> SP, AR** + + - По фронту пустит значение указателя стека в АЛУ и прибавит 1. + + - По спаду запишет полученное значение в указатель стека и в адресный регистр. + +- 3 такт: **MEM(AR) -> DR** + + - По фронту найдёт ячейку по адресу. + + - По спаду запишет значение этой ячейки в регистр данных. + +- 4 такт: **DR -> IP** + + - По фронту пустит значение регистра данных в АЛУ. + + - По спаду запишет это значение в счетчик команд. + +- 5 такт: **SP + 1 -> SP** + + - По фронту пустит значение указателя стека в АЛУ и прибавит 1. + + - По спаду запишет полученное значение в указатель стека. + +*Флаги, соответственно, возьмутся из регистра состояния.* + +Цикл выборки адреса выполняться не будет, так как команда безадресная. + +--- + +## Источники + +[Методические указания к предмету](https://se.ifmo.ru/documents/10180/38002/Методические+указания+к+выполнению+лабораторных+работ+и+рубежного+контроля+БЭВМ+2019+bcomp-ng.pdf/d5a1be02-ad3f-4c43-8032-a2a04d6db12e) + +[Подсказка от моего друга и одногруппника](https://github.com/dxunvrs/ITMO/blob/master/OPD/Lab4/lab4_hint.md) + +И конечно всеми любый гугл (вообще, яндекс поисковик, но это не важно). diff --git a/main.asm b/main.asm new file mode 100644 index 0000000..3a855e0 --- /dev/null +++ b/main.asm @@ -0,0 +1,46 @@ +ORG 0x05C6 +START: CLA +ST result +LD X +INC +PUSH +CALL 0x06E5 +POP +ADD result +ST result +LD Z +PUSH +CALL 0x06E5 +POP +ADD result +ST result +LD Y +DEC +PUSH +CALL 0x06E5 +POP +SUB result +ST result +HLT +Z: WORD 0xFFF4 +Y: WORD 0x0000 +X: WORD 0xFDDE +result: WORD ? + +ORG 0x06E5 +LD &1 +BEQ A +BPL B +A: CMP const1 +BLT B +BEQ B +ASL +ASL +SUB &1 +ADD const2 +JUMP C +B: LD const1 +C: ST &1 +RET +const1: WORD 0xFAB3 +const2: WORD 0x0064 \ No newline at end of file diff --git a/report.pdf b/report.pdf new file mode 100644 index 0000000..f36c4d3 Binary files /dev/null and b/report.pdf differ