В мир информатики # 81 (16—30 ноября).
Моделирование
Моделирование работы ЭВМ с помощью
программы
Microsoft Excel
Окончание. Начало см. “В мир
информатики” № 80 (“Информатика” №
21/2006)
Е.А. Еремин,
г. Пермь
Перейдем к непосредственному
моделированию описанной в первой части статьи
учебной ЭВМ “Кроха”.
Прежде всего подчеркнем, что для
реализации даже простейшей автоматически
работающей модели наличие внутреннего языка
программирования является обязательным; в
частности, язык VBA (Visual Basic for Application)
в Excel содержит более чем достаточное для наших
целей количество разнообразных средств.
И еще одно важное для понимания
дальнейшего замечание. Хотя оригинальная
“Кроха” для наглядности описывается в двоичной
системе (см. [1]), при моделировании в Excel удобнее
воспользоваться восьмеричной; в последнем
случае команда представляет собой четыре
восьмеричных цифры, причем каждая из них
соответствует отдельной части команды (см.
структуру трехадресной команды в первой части
статьи). С точки зрения простоты представления
команд это обстоятельство необычайно удобно.
Реализацию “Крохи” в клетках
электронной таблицы начнем с планирования
назначения ячеек. Предусмотрев место под
заголовки и тексты пояснений, разместим ячейки
памяти нашей ЭВМ в блоке ячеек B4:E11. Количество
строк очевидным образом равняется числу ячеек,
причем любая из них делится на четыре части: код
операции и три адреса. Таким образом, при наборе
команды каждая из четырех цифр заносится в
отдельную клетку, как это сделано на рис. 1.
Рядом с “ОЗУ” в группе клеток F4:G6
разместим дисплей, отображающий содержимое
адресов ОЗУ в восьмеричной и десятичной системах
счисления. Наконец, в строках 13–15 расположим
описанные ранее регистры АЛУ и УУ. Все остальные
строки есть просто справочный материал.
Картину завершают две кнопки
управления — Start и Step, первая из которых
служит для запуска исполнения всей программы, а
вторая — только одной ее очередной команды.
Последняя возможность позволяет производить
пошаговое выполнение программы, что особенно
удобно при отладке.

Рис. 1. Общий вид ЭВМ “Кроха” в
электронной таблице
После выделения цветом фона ячеек,
соответствующих различным устройствам машины, и
нанесения необходимых подписей перейдем к
написанию программы. Ее назначение состоит в том,
чтобы реализовать исполнение основного
алгоритма “Крохи”. Полный листинг программы
приводится ниже.
Rem "Расположение" устройств
машины в таблице
Rem ОЗУ
Const Mem_cell As Integer = 4
Rem Счетчик команд
Const IP_cell As Integer = 13
Rem Регистр команд
Const RK_cell As Integer = IP_cell + 1
Rem Сумматор
Const SM_cell As Integer = IP_cell + 2
Rem Дисплей
Const DI_cell As Integer = Mem_cell
Rem Регистр команд
Const Left_cell As Integer = 2
Rem Сообщение об ошибке
Const Msg_cell As Integer = DI_cell + 3
Const Msg_left As Integer = Left_cell + 4
Rem Переменные
Dim doing As Boolean 'True - программа
выполняется, False - стоп
Rem **ВСПОМОГАТЕЛЬНЫЕ ПРОЦЕДУРЫ И
ФУНКЦИИ**
Function Oct4(n) As String
Rem Функция возвращает 4 восьмеричные
цифры
Rem числа n (например, "0032")
Oct4 = Right$("000" + Oct$(n), 4)
End Function
Function Get_memory_digit(adr, n) As Integer
Rem Возвращает из заданной ячейки ОЗУ
Rem заданную восьмеричную цифру
Rem Цифры, как и ячейки ОЗУ, нумеруются с
0 (до 3)
Get_memory_digit = Cells(Mem_cell + adr, Left_cell + n)
End Function
Function Get_memory_cell(adr) As Integer
Rem Преобразует ячейку ОЗУ в десятичное
число
Rem из восьмеричной системы счисления
Dim i, m, r As Integer
r = 0: m = 1
For i = 3 To 0 Step - 1
r = r + m * Get_memory_digit(adr, i)
m = m * 8
Next i
Get_memory_cell = r
End Function
Sub Put_memory_cell(adr, d$)
Rem Функция Записывает в ОЗУ по адресу adr
Rem четыре восьмеричные цифры из строки
d$
Dim i As Integer
Rem Запишем в ОЗУ отдельные цифры
For i = 0 To 3
Cells(Mem_cell + adr, Left_cell + i) = Mid$(d$, i + 1, 1)
Next i
End Sub
Sub Copy_Cells(d, s)
Rem Процедура копирует четыре
восьмеричные цифры
Dim i As Integer
For i = 0 To 3
Cells(d, Left_cell + i) = Cells(s, Left_cell + i)
Next i
End Sub
Sub Avost(m$) 'Аварийный останов
doing = False
'Вывод сообщения
Cells(Msg_cell, Msg_left) = m$
End Sub
Rem ** ОСНОВНЫЕ ПРОЦЕДУРЫ И ФУНКЦИИ **
Sub Do_command()
Rem Процедура выполняет одну очередную
команду
Dim i, a, d, IP, KOP, OP1, OP2, RE As Integer, s As String
Rem Очистка ошибки
Cells(Msg_cell, Msg_left) = ""
Rem Извлечение команды из ОЗУ в РК
IP = Cells(IP_cell, Left_cell)
Rem Копирование команды из ОЗУ в РК
Call Copy_Cells(RK_cell, Mem_cell + IP)
Rem Увеличение СК
i = Cells(IP_cell, Left_cell): i = i + 1
If i > 7 Then i = 0
Cells(IP_cell, Left_cell) = i
Rem Операция
KOP = Cells(RK_cell, Left_cell)
OP1 = Get_memory_cell(Cells(RK_cell, Left_cell + 1))
OP2 = Get_memory_cell(Cells(RK_cell, Left_cell + 2))
On KOP + 1 GoSub c_mov, c_add, c_div, c_sub, c_beq, c_mul, c_bgt, c_hlt
If (KOP > 3) And (KOP <> 5) Then Exit Sub 'нет записи
результата
Rem Проверка и запись результата
GoSub Overflow 'Проверить переполнение
Rem Занести результат в десятичном виде
Cells(SM_cell, Left_cell + 3) = RE
Rem Перевести результат в восьмеричную
с.с.
s = oct4(RE)
Rem адрес для записи из РК (Aдрес 3)
a = Cells(RK_cell, Left_cell + 3)
Rem Запись результата в ОЗУ
Call Put_memory_cell(a, s)
Rem 'Скопировать число из ОЗУ в сумматор
Call Copy_Cells(SM_cell, Mem_cell + a)
Exit Sub
overflow: 'Проверка переполнения
(результат < 4096)
If RE > 4095 Then
RE = 4095
Call Avost("> 4095")
End If
Return
Rem Система команд
c_mov: RE = OP1: Return
c_add: RE = OP1 + OP2: Return
c_sub: RE = Abs(OP1 - OP2): Return
c_mul: RE = OP1 * OP2: Return
c_div:
If OP2 <> 0 Then
RE = Int(OP1 / OP2)
Else: Call Avost("/ 0")
End If
Return
c_beq: If OP1 = OP2 Then
Cells(IP_cell, 2) = Cells(RK_cell, 5)
End If
Return
c_bgt: If OP1 > OP2 Then
Cells(IP_cell, 2) = Cells(RK_cell, 5)
End If
Return
c_hlt: doing = False
For i = 0 To 2 'вывод трех чисел
REM Адрес ОЗУ (берем из РК)
a = Cells(RK_cell, 3 + i)
REM Число
d = Get_memory_cell(a)
REM Десятичный вывод
Cells(DI_cell + i, Left_cell + 5) = d
REM Восьмеричный вывод
Cells(DI_cell + i, Left_cell + 4) = oct4(d)
Next i
Return
End Sub
Sub Do_program()
REM Процедура выполняет всю программу
REM Очистка СК
Cells(IP_cell, Left_cell) = 0
doing = True
Do
Do_command
Loop Until Not doing
End Sub
Объясним основные моменты
“устройства” приведенной программы.
Константы, описанные в начале
программы, обеспечивают возможность размещения
функциональных блоков “Крохи” в любом месте
листа электронной таблицы. Например, для
авторской реализации ячейки ОЗУ расположены
начиная с четвертой строки, а счетчик команд
находится в тринадцатой.
Далее в листинге следуют
вспомогательные процедуры и функции:
· функция Oct4 преобразует к
стандартному виду произвольное восьмеричное
число, добавляя перед сохранением в ОЗУ
необходимое количество незначащих нулей слева;
· функция Get_memory_digit возвращает из
заданной ячейки ОЗУ заданную восьмеричную цифру;
· функция Get_memory_cell, используя
предыдущую функцию, считывает из ОЗУ десятичное
число; фактически она производит перевод числа
из восьмеричной системы счисления в десятичную;
· процедура Put_memory_cell заносит в клетки
таблицы, относящиеся к заданной ячейке ОЗУ,
восьмеричное число из строковой переменной;
· процедура Copy_cells копирует
четырехзначное восьмеричное число, которое
занимает четыре смежные горизонтальные ячейки,
из одной строки таблицы в другую;
· наконец, процедура Avost обслуживает
аварийный останов в случаях деления на ноль или
переполнения.
Собственно логика функционирования
учебной ЭВМ “Кроха” сосредоточена в двух
основных процедурах, каждая из которых связана
со своей кнопкой. Первая — Do_command — выполняет
одну очередную команду (процедура вызывается по
щелчку на кнопке Step). Вторая — Do_program —
организует полное выполнение программы,
производя все подготовительные действия и
циклически вызывая предыдущую процедуру.
Прекращение выполнения обеспечивается
установкой у переменной doing значения False.
Данное действие обеспечивается внутри процедуры
do_command по команде “Стоп” (в программе — по метке
c_hlt) или в случаях аварийных ситуаций типа
деления на ноль.
С точки зрения целей нашего
моделирования следует подчеркнуть, что
процедура do_command отчетливо повторяет основной
алгоритм работы процессора, описанный в первой
части статьи. Используя имеющиеся в тексте
программы комментарии, легко проследить
основные этапы выполнения команды: считывание
очередной инструкции, увеличение счетчика
команд и выполнение выбранной в регистр команд
операции. Последний этап, в свою очередь, делится
на извлечение адресов Aдрес 1 и Aдрес 23, их
обработке согласно коду операции и, если выбрана
одна из арифметических инструкций или перепись,
записи полученного результата. Команды перехода
и остановки имеют определенную специфику
выполнения: первые проверяют требуемое условие и
в случае его выполнения заносят в счетчик
величину Aдрес 3 команды, а инструкция останова
обслуживает вывод всех трех своих адресов на
дисплей. Таким образом, все разнообразие
поведения при выполнении различных команд
“Крохи” обеспечивается оператором выбора On KOP + 1
GoSub …, где переменная KOP есть не что иное, как код
исполняемой инструкции.
Учитывая подробные комментарии,
читателям нетрудно будет разобраться в
приведенном листинге.
Остается только ввести полученную
программу. Для этого сначала создадим самый
первый макрос, воспользовавшись меню Сервис |
Макрос | Макросы… После этого
внимательным образом наберем весь текст
программы (напомним читателям, что в любой момент
можно вернуться в редактор языка Visual Basic, нажимая
сочетание клавиш Alt и F11).
Наконец, последнее, что нам предстоит
сделать, — это связать управляющие кнопки с
соответствующими процедурами (макросами).
Учебная ЭВМ “Кроха” готова!
Для тестирования введем программу
вычисления факториала, которая была разобрана
ранее (перед вводом полезно еще раз внимательно
рассмотреть расположение информации в ячейках
таблицы на рис. 1). Нажмем кнопку Start и
убедимся в том, что получился правильный
результат.
Итак, пользуясь табличным процессором
Microsoft Excel, мы смоделировали работу ЭВМ. Остается
внимательно пронаблюдать за тем, как “Кроха”
выполняет программу, обратив внимание на
следующие моменты:
· каким образом выполняется линейный
участок программы, команды которого расположены
в памяти последовательно (практическая
реализация принципа программного управления);
· как реализуется условный переход,
благодаря которому возможны разветвляющиеся и
циклические программы;
· любая инструкция ЭВМ есть указание
на действия, которые необходимо сделать над
указанной в ней информацией; команды максимально
универсальны и их набор ограничен;
· обращение к информации в ОЗУ
происходит по адресам (принцип адресности);
· программы и данные хранятся в общей
памяти и с точки зрения хранения не имеют
принципиальных различий (принцип хранимой
программы);
· диапазон допустимых данных в машине
ограничен; он определяется разрядностью, при
превышении которой происходит особая ситуация —
переполнение.
Таким образом, мы видим, что изучение
описанной в статье задачи позволяет
проиллюстрировать наиболее фундаментальные
принципы устройства современных компьютеров.
Учитывая простоту (даже, можно сказать,
примитивность) модели “Кроха”, такой результат
для некоторых читателей может оказаться
неочевидным.
Литература
1. Основы информатики и вычислительной
техники: Пробное учебное пособие для средних
учебных заведений. / А.Г. Гейн, В.Г. Житомирский,
Е.В. Линецкий и др. Свердловск: Изд-во Уральского
ун-та, 1989. |