462 lines
21 KiB
Markdown
462 lines
21 KiB
Markdown
# Гайд по 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)
|
|
|
|
И конечно всеми любый гугл (вообще, яндекс поисковик, но это не важно).
|