4911

Разработка программы-эмулятора для заданной гипотетической ЭВМ

Курсовая

Информатика, кибернетика и программирование

В настоящее время получило широкое распространение использование микропроцессоров в качестве встроенных элементов систем автоматического управления,в том числе как управляющих блоков периферийных узлов вычислительных комплексов. Функции...

Русский

2012-11-29

2.3 MB

23 чел.

В настоящее время получило широкое распространение использование микропроцессоров в качестве встроенных элементов систем автоматического управления, в том числе как управляющих блоков периферийных узлов вычислительных комплексов. Функции, возлагаемые в такой системе на микропроцессор, полностью определяются программой, хранимой в его памяти. Поскольку программа работы встроенного микропроцессора изменяется сравнительно редко, к параметрам этой программы и к надежности ее функционирования предъявляются особенно жесткие требования. В связи с этим являются обязательными тщательная отладка и всестороннее тестирование программы работы микропроцессора.

Микропроцессоры имеют, как правило, ограниченные возможности  ввода-вывода программ и обрабатываемых данных, что затрудняет выполнение работ по отладке программ. Такие работы также затруднены или вообще невозможны при разработке новых микропроцессорных систем. Всё это стимулирует использование универсальных ЭВМ для отладки и тестирования программ микроЭВМ и микропроцессоров, т.е. использование методики эмуляции программ.

Темой курсовой работы является разработка программы-эмулятора для заданной гипотетической ЭВМ, в упрощенном виде воссоздающей структуру реальной машины. Эмуляция выполняется на ПЭВМ в операционной среде MS DOS, рабочим языком программирования является язык Турбо Паскаль.

1.  СОДЕРЖАНИЕ  КУРСОВОЙ  РАБОТЫ

Тематика курсовых работ связана с созданием программ-эмуляторов для учебных ЭВМ со сравнительно простой структурой. Студенту выдается функциональная схема ЭВМ и набор команд, выполняемых данной машиной. После изучения принципа работы ЭВМ и порядка выполнения её команд студент разрабатывает программную модель на языке Турбо Паскаль и проверяет её работу на тестовых примерах. Такими примерами служат небольшие программы в машинных кодах учебной ЭВМ, организующие вычисления по формулам, согласованным с преподавателем.

По окончании выполнения курсовой работы студент оформляет отчет в соответствии с требованиями, изложенными в настоящих методуказаниях, и защищает его.

График выполнения курсовой работы и содержание отчета регламентируются техническим заданием, которое подписывается студентом и утверждается руководителем курсовой работы.

Основные этапы разработки программы-эмулятора детально описаны ниже на примере гипотетической ЭВМ, которой условно присвоено название М1. Внимательное изучение предлагаемой методики является обязательным для успешного выполнения курсовой работы. При этом следует иметь в виду, что структуры ЭВМ, выдаваемые студентам в техническом задании к курсовой работе, могут существенно отличаться от структуры машины М1, поэтому механический перенос фрагментов эмулятора М1 на другие структуры ЭВМ в общем случае невозможен.

 УЧЕБНАЯ ВЫЧИСЛИТЕЛЬНАЯ МАШИНА М1

2.1   Архитектура ЭВМ М1

Структурная схема ЭВМ М1 приведена на  рис.1. В состав ЭВМ входят следующие узлы:

  •  оперативная память MEMORY емкостью 256  8-разрядных ячеек, предназначенная для хранения команд и данных, используемых в программе;
  •  восьмиразрядный счетчик адреса команд   SAK, предназначенный для хранения адреса следующей команды;
  •  восьмиразрядный регистр адреса  RA, определяющий адрес ячейки памяти, в которую записывается или из которой читается информация;
  •  восьмиразрядный буферный регистр слова RS для временного хранения читаемой или записываемой информации;
  •  шестнадцатиразрядный регистр команд RK, хранящий выполняемую команду;
  •  сумматор адреса SA, предназначенный для формирования исполнительного адреса операнда;
  •  шестнадцатиразрядные операционные регистры OR1 и OR2 для временного хранения операндов;
  •  блок из четырех шестнадцатиразрядных регистров R с номерами  0, 1, 2, 3;
  •  арифметико-логическое устройство АЛУ, выполняющее операцию, заданную кодом операции команды;
  •  шестнадцатиразрядный регистр результата RES, предназначенный для временного хранения результата операции, выполняемой АЛУ;
  •  дешифратор кода операции DC, осуществляющий настройку АЛУ на выполнение очередной команды;
  •  четырехразрядный регистр признаков RP.

 

При выполнении арифметической операции первый бит RP устанавливается в «1», если ее результат равен нулю; второй бит устанавливается в «1» при отрицательном, а третий бит  при положительном результате этой операции; четвертый бит устанавливается в «1» в случае некорректности выполнения операции (переполнение регистра результатов RES или попытка деления на нуль).

Для логических операций и для команд сдвига производится лишь анализ результата на равенство нулю: RP[1] = 1, если результат операции равен нулю; RP[2] = 1, если этот результат не равен нулю.

В состав команды входят следующие поля:

  •  код выполняемой операции KOP (биты 1 –);
  •  модификатор адреса МА (биты 5 и 6);
  •  номер регистра NR (биты 7 и 8);
  •  адрес ячейки памяти AM (биты 9 –).

Адреса ячеек изменяются от 0 до 255 (от 00000000 до 11111111 в двоичной системе счисления).

Обрабатываемыми данными для арифметических операций являются 16-разрядные целые числа, причем первый разряд определяет знак числа, остальныедвоичные цифры числа. Отрицательные числа представлены в дополнительном коде. В логических операциях также используются 16-разрядные операнды, которые рассматриваются как последовательности битов.

Команды программы и обрабатываемые данные занимают две смежные ячейки памяти, при этом адрес первой ячейки всегда должен быть четным.

В качестве первого операнда в двухместных операциях принимается содержимое регистра R, номер которого определяется значением поля NR регистра команд RK. Формирование второго операнда зависит от типа адресации, определяемой значением модификатора адреса МА:

МА = 00   = АМ –прямая адресация;

MA = 01   = MEMORY(AM) –косвенная адресация;

МА = 10  OР2 = AM –непосредственная адресация. 

МА = 11   = АМ +() –индекс-адресация;

Здесь  ОР2условное обозначение второго операнда, которым в данном случае является непосредственно значение поля АМ регистра команд RK, а не содержимое ячейки памяти с адресом АМ.

В качестве индексного регистра всегда используется нулевой регистр  блока R.

При прямой, косвенной и индекс-адресации , где исполнитеьный адрес  определяет адрес левого байта поля длиной два байта. При непосредственной адресации операнды имеют длину один байт, первый операнд размещается в битах  9регистра  OR1, второй операндв битах  9регистра OR2. При этом биты  1регистров OR1 и OR2 должны быть нулевыми.

2.2  Выполнение команд в ЭВМ M1

Система команд ЭВМ M1, приведенная в табл.1, включает в себя:

  •  команды выполнения операций с блоком регистровЗагрузка операнда» и «Сохранение операнда»);
  •  арифметико-логические командыСложение», «Вычитание», «Умножение», «Деление», «Сравнение», «Конъюнкция», «Дизъюнкция», «Сложение по модулю 2»);
  •  команды сдвигаСдвиг влево логический» и «Сдвиг вправо логический»);
  •  команды управления порядком выполнения программыПереход», «Вызов подпрограммы», «Возврат из подпрограммы», «Останов»).

Таблица 1. Система команд ЭВМ М1

Код

опер.

Наименование

Признаки

Выполнение

команды

=

<

>

нк

0000

Останов

0001

Загрузка операнда

+

+

+

0010

Сохранение операнда

0011

Сложение

+

+

+

+

0100

Вычитание

+

+

+

+

0101

Умножение

+

+

+

+

0110

Деление

+

+

+

+

0111

Конъюнкция

+

+

1000

Дизъюнкция

+

+

1001

Сложение по модулю 2

+

+

1010

Сдвиг влево логический

+

+

1011

Сдвиг вправо логический

+

+

1100

Переход

См.описание

1101

Сравнение

+

+

+

1110

Обращение к подпрограмме

1111

Возврат из подпрограммы

Круглые скобки в графе «Выполнение команды» означают содержимое регистра или ячейки памяти. Например, запись   –это адрес ячейки, а () –содержимое ячейки с адресом .

В табл.1   - это  i –ый  регистр блока R, ОР2второй операнд, формирование которого зависит от вида адресации.

КомандаЗагрузка операндапересылает содержимое двух байт оперативной памяти, адрес которых задан значением , в регистр , номер которого определяется значением NR. При непосредственной адресации эта команда посылает в биты  9регистра  (i = 0 .. 3) значение компонента AM регистра команд RK, при этом биты  1 .. 8  регистра  обнуляются. Команда «Сохранение операнда» осуществляет обратную операциюпересылку данных из регистра  в память. При выполнении команды «Загрузка операнда» вырабатывается признак результата, определяющий содержимое соответствующих разрядов регистра RP: RP[1] = 1, если пересылаемое значение равно нулю; RP[2] = 1, если это значение меньше нуля;  RP[3] = 1, если оно больше нуля.

В арифметико-логических командах первый операнд выбирается из регистра , а расположение второго операнда определяется полями МА и АМ регистра RK. Признаки завершения операции, которые вырабатываются при выполнении рассматриваемых команд, представлены в табл.1. В частности, признак «нк» (некорректность операции) означает, что в результате выполнения данной операции возникает переполнение регистра результатов Res или же здесь отмечена попытка деления на нуль.

Символ” в графе признаков табл.1 определяет ситуацию, которая не может возникнуть в данной операции (например, некорректность при выполнении операции сдвига), или то, что данная операция не изменяет регистр RP (например, команда перехода).

Сущность изменения регистра RP рассмотрим на конкретном примере. Предположим, что в программе выполнена команда сложения и при этом получен положительный результат. Тогда в состояние «1» должен быть установлен лишь третий бит регистра RP, остальные биты  должны быть сброшены на нуль.

Примечание. Если в команде, приведенной в табл.1, все графы признаков отмечены символом ”, то это означает лишь то, что при этом сохраняются предыдущие значения признаков (но не выполняется сброс их на нуль). 

Некоторую специфику в данной группе имеет команда сравнения. При ее выполнении вырабатываются только признаки завершения операции: RP[1] = 1, если сравниваемые операнды равны друг другу;  RP[2] = 1, если первый операнд меньше второго;  RP[3] = 1, если первый операнд больше второго операнда. Содержимое регистра RES при этом не изменяется.

В командах логического сдвига первый операнд ОР1 выбирается из регистров , пересылается в регистр OR1, сдвигается влево или вправо, а затем через регистр RES пересылается на тот же регистр . Освобождаемые при выполнении операции разряды в левой или в правой части регистра OR1 заполняются нулями. Количество сдвигов определяется операндом ОР2, поступающим на регистр OR2. В зависимости от типа адресации в качестве операнда ОР2 берется исполнительный адрес   или  значение АМ при непосредственной адресации. Если  ОР2 > 15, то сдвиг регистра OR1 не производится, но во все его разряды записываются нули.

В команде перехода биты  5 ––это поле маски. Если логическое произведение содержимого маски и содержимого регистра признаков отличается от нуля, то осуществляется переход по адресу , т.е. следующей исполняемой командой программы будет команда с адресом . Если маска  М=1111, то управление передается по адресу  вне зависимости от содержимого регистра RP (безусловный переход). Если  М = 0000, то выполняется следующая команда (команда перехода в этом случае эквивалентна пустой команде). В команде перехода всегда используется косвенная адресация, т.е.  = MEMORY(AM).

Частные случаи значения маски:

- М = 0000    - пустая команда (нет передачи управления);

- М = 1000    - условный переход по нулю;

- М = 0010    - условный переход по «больше»;

- М = 1100    - условный переход по нулю или по «меньше»;

………………….

- М = 1111    - безусловный переход.

Значение  М = 0001  определяет переход по признаку некорректности. В этом случае необходимо по адресу АМ перейти на вывод сообщения об аварийном прерывании, указав при этом код операции и адрес команды, вызвавшей прерывание, после чего произвести останов ЭВМ.

По команде «Обращение к подпрограмме» содержимое счетчика адреса команд SAK (адрес следующей команды) временно запоминается в регистре  в соответствии с номером NR, а в регистр SAK загружается значение исполнительного адреса . Тогда следующей исполняемой командой будет команда с адресом  (в данном случае команда входа в подпрограмму).

При выполнении команды возврата из подпрограммы в регистр SAK переписывается содержимое регистра . Эта команда ставится последней в подпрограмме и обеспечивает возврат на продолжение работы основной программы. В данной команде биты  9не используются.

В команде останова принимается во внимание лишь код операции. Значения битов 5на выполнение команды влияния не оказывают.

В системе команд ЭВМ М1 имеется ограничение на использование непосредственной адресации операндов. Этот вид адресации неприменим для команд  0010, 1100, 1110, 1111Запись в память», «Переход», «Вызов подпрограммы», «Возврат из подпрограммы»). 

Выполнение машинной программы начинается с команды, адрес которой определяется значением пускового адреса, загруженного в регистр SAK. В дальнейшем содержимое этого регистра указывает адрес каждой очередной выполняемой команды программы. Нормальное завершение работы машинной программы имеет место при достижении команды останова. Если при выполнении какой-либо команды выработан признак некорректности (RP[4] = 1), то это рассматривается как аварийное завершение работы программы; при этом работа программы прерывается, а на экран должно быть выведено сообщение о причине прерывания.

Выполнение любой команды начинается с загрузки содержимого поля памяти, адрес которого задан регистром RK, через буферный регистр RS в регистр команд RK. Для подготовки выборки следующей команды содержимое регистра SAK увеличивается на 2 (каждая команда ЭВМ М1 занимает две смежные ячейки памяти). После этого из регистра RK выделяются поля KOP, MA, NR, AM. Дешифратор DC анализирует значение кода операции и определяет команду, которая должна выполняться в данный момент (количество входов дешифратора равно количеству разрядов в КОР, количество выходов равно количеству машинных команд).

Примечание.

Если КОП имеет m разрядов, то дещифратор должен иметь  выходов, что однозначно определяет возможное максимальное количество команд данной ЭВМ.

Следующим этапом является формирование исполнительного адреса, если он используется в данной команде. При этом анализируется значение модификатора адреса МА. 

Если  МА = 00 (прямая адресация), то содержимое поля АМ регистра команд  RK передается в регистр адреса RA. 

Если  МА = 01 (косвенная адресация), то в регистр адреса RA посылается значение  АМ+1 (это местонахождение адресной части команды с адресом АМ), по этому адресу выбирается ячейка памяти, ее содержимое поступает в буферный регистр RS, а затем переписывается в регистр RA. 

Если  МА = 11  (индекс-адресация), значение адреса АМ суммируется в SA c содержимым регистра , результат суммирования передается в регистр RA. По сформированному значению содержимого регистра RA из памяти последовательно выбираются ячейки с адресами  и +1, содержимое которых затем через регистр RS записывается соответственно в разряды  1и  9регистра OR2.

При  МА = 10  (непосредственная адресация) содержимое поля АМ регистра RK записывается в разряды  9регистра OR2. Значение первого операнда из регистра  пересылается в регистр OR1. Результат операции формируется в регистре  RES и, если это предусмотрено кодом операции, пересылается в тот же регистр .

2.3. Составление программы на машинном языке ЭВМ M1

На первом этапе выполнения курсовой работы необходимо составить тричетыре программы на машинном языке заданной ЭВМ таким образом, чтобы в этих программах были отражены все команды ЭВМ и особенности их выполнения, в частности типы адресации операндов. В последующем эти программы будут использованы как тестовый материал для проверки работы спроектированного эмулятора.

Машинную программу целесообразно сначала записать в условных кодах, что обеспечивает более высокий уровень ее читаемости и уменьшает количество возможных ошибок. При программировании в условных кодах вместо двоичных кодов машинных операций и типов адресации записывают их символические обозначения, вместо двоичного номера регистраего десятичный номер, вместо реального двоичного адреса операндасимволическое обозначение этого операнда. 

Описанная выше методика близка к методике обозначений в языке Ассемблер. Например, команда сложения могла бы иметь следующий вид:

Add   I, 2, X

Здесь  

  •  Add  –условное обозначение кода операции;
  •  Iуказание на индекс-адресацию;
  •  2номер регистра для первого операнда;
  •  Xсимволический адрес ячейки памяти, в которой содержится переменная Х.

Тем не менее указанный способ содержит определенные недостатки, если рассматривать его применительно к разработке эмулятора. Программа на Ассемблере, символически отображающая структуры машинных команд, удобна при ее разработке. Однако дальнейшую работу, в частности преобразование в машинные команды и распределение памяти для команд, переменных и констант, выполняет компилятор. В то же время при разработке эмулятора эту работу приходится выполнять вручную. Поэтому представляется более целесообразным использовать символические обозначения машинных команд, наиболее близкие к структуре этих команд, что облегчает в дальнейшем их окончательное преобразование.

В ЭВМ М1 машинная команда разделяется на 4 поля: код операции, модификатор адреса, номер регистра и адрес операнда.

Код операции целесообразно представлять символически, используя обозначения, которые применяются в языке Ассемблера. В данном случае можно принять:

Haltостанов (код 0000);

Loadзагрузка операнда (код 0001);

Stсохранение операнда (код 0010);

Addсложение (код 0011);

Subвычитание (код 0100);

Mulумножение (код 0101);

Divделение (код 0110);

Andконъюнкция (код 0111);

Orдизъюнкция (код 1000);

Xorсложение по модулю 2 (код 1001);

ShLсдвиг влево логический (код 1010);

ShRсдвиг вправо логический (код 1011);

Jumpпереход (код 1100);

Cmpсравнение (код 1101);

Callвызов подпрограммы (код 1110);

Retвозврат из подпрограммы (код 1111).

Модификатор адреса имеет лишь 4 значения: 00 (прямая адресация), 01 (косвенная адресация), 10 (непосредственная адресация) и 11 (индекс-адресация). Их нет смысла заменять символическими именами.

Аналогичная ситуация имеет место с номерами регистров, также имеющими 4 значения: 00, 01, 10 и 11.

В команде перехода четырехразрядную маску целесообразно изображать в виде двух групп по два разряда аналогично командам, содержащим модификатор адреса и номер регистра.

Обозначение адреса операнда зависит от вида адресации. При непосредственной адресации значением операнда является 8-разрядное целое неотрицательное число  от 0 до 255. Его целесообразно записывать в 10 с/с. При прямой и индекс-адресации нужно указывать адрес операнда. Для этого целесообразно использовать обозначение  < x >, определяющееадрес поля памяти, где расположена переменная х.

Примечание. Если константа в программируемом выражении превышает значение 255 (максиально возможное значение при непосредственной алресации ) и равна, например, 310, то соответствующий операнд следует обозначить <310>, что по форме записи будет отличаться от обозначений операнда при непосредственной адресации, т.е. <310> –это не число со значением 310, а адрес ячейки памяти, в которой записано такое число.

Каждая машинная команда имеет конкретный адрес в оперативной памяти, причем этот адрес должен быть четным. Поскольку в командах перехода и вызова подпрограммы используется адрес машинной команды, то слева от символической записи каждой команды будем указывать ее адрес. Тогда приведенная выше команда сложения будет иметь вид

k+10    Add  11  10  < x >,

где  k –пусковой адрес программы.

Специфику обозначения косвенной адресации рассмотрим на примере команды перехода.

В соответствии с описанием ЭВМ М1 операндом в команде перехода яввляется адрес поля памяти, в котором записан адрес перехода. Предположим, что при реализации разветвляющейся программы необходимо осуществить безусловный переход на машинную команду с адресом  k+20. Этот адрес необходимо предварительно записать в какую-либо конкретную ячейку памяти, например, в ячейку  k+40, расположенную вне исполняемых команд, во всяком случае после команды останова. Тогда подготовку адреса перехода можно осуществить следующим образом:

Load  10  11  k+20   { непосредственная адресация, }

                            { регистр R3 }

St    00  11  k+40   { прямая адресация, регистр R3 }

Команда загрузки  Load, в которой задана непосредственная адресация, записывает в регистр    значениеадреса перехода, после чего команда сохранения операнда  St  с прямой адресацией пересылает этот адрес из регистра  в поле памяти с адресом  k+40  (здесь имеется в виду, что адрес k+40 находится вне пределов адресов исполняемых команд).  

Тогда команда безусловного перехода будет иметь вид

Jump   11  11  k+40, где маска 1111 означает безусловный переход.

Примечание. Здесь уместно напомнить, что записанная выше команда, имея в своем описании косвенную адресацию, выполняет передачу управления не по адресу k+40, а по адресу  k+20.

Аналогичным образом подготавливается косвенная адресация и для других машинных команд, но в этом случае модификатор адреса должен иметь  значение 01.

Рассмотрим теперь примеры, аналогичные тестам  1, 2  и  3, приведенным в приложении 2 методических указаний.

Пример 1.

Результат решения должен быть  

k+0    Load 00 01  < a >    

k+2    Sub  10 01    1      

k+4    St   00 01    P1     

k+6    Load 00 01  < a >    

k+8    Mul  00 01  <330>    

k+10   St   00 01    P2     

k+12   Load 00 01  < b >    

k+14   Mul  10 01    28     

k+16   Add  00 01    P2     

k+18   Div  00 01    P1     

k+20   St   00 01    P1     

k+22   Load 00 01  < a >    

k+24   Mul  00 01  < b >    

k+26   Mul  10 01     8     

k+28   Add  00 01    P1     

k+30   St   00 01  < y >    

k+32   Halt                 

k+34      a = 10

k+36      b = -4

k+38      330

k+40      y

k+42      P1

k+44      P2

В этой программе имеются 4 константы. Поскольку значения  1, 8, 28  меньше  255, то для их представления в машинных командах используется непосредственная адресация, в то время как для константы  330  отводится отдельная ячейка памяти.

Обозначения R1 – это номер регистра в блоке R,  P1 и P2  в поле операндаэто адреса ячеек памяти, предназначенные для временного хранения промежуточных результатов.

Предположим, что в качестве пускового адреса программы задано значение 20, а в качестве исходной системы счисления  –с/с.  Тогда вначале производится преобразование символьной записи программы в 2 с/с, а затемв 16 с/с. Фактически такое представление программыэто содержимое входного текстового файла. В первой строке этого файла записывается в 10 с/с пусковой адрес программы, а затем машинные команды, переменные и константы в заданной системе счисления. 

Для рассматриваемого примера будем иметь (слева всё, кроме пускового адреса, в 2 с/с, справав 16 с/с:

     20                   20

00 01 00110110       1136

10 01 00000001       4901

00 01 00111110       213E

00 01 00110110       1136

00 01 00111010       513A

00 01 01000000       2140

00 01 00111000       1138

00 01 00011100       511C

00 01 01000000       3140

00 01 00111110       613E

00 01 00111110       213E

00 01 00110110       1136

00 01 00111000       5138

10 01 00001000       5908

00 01 00111110       313E

01 01 00111100       253C

00 00 00000000       0000

0000 00 00 00001010       000A    значение а

1111 11 11 11111100       FFFC    значение b

0000 00 01 01001010       014A    значение 330

Результат  работы программы  (k+40) = 3310 = 2116 = 001000012 .

Необходимо обратить внимание, что адреса операндов в этой программе записаны вначале в двоичной, а затем в шестнадцатеричной системе счисления с учетом пускового адреса. Например,

<a> = (k+34)10 = 5410 = 3616 = 001101102

Поля памяти с адресами  < y >, P1 и P2 в машинной записи программы не отображены, поскольку их содержимое не вводится извне, а формируется в программе.

Примечание. Если в качестве входной системы счисления задана 8 с/с, то машинное двоичное представление программы разделяется справа налево на триады, после чего каждая триада записывается одной восьмеричной цифрой. Если задана четверичная система счисления, то аналогично производится разделение двоичной записи программы справа налево, но по два разряда, значения которых затем изображаются четверичными цифрами  0, 1, 2 или 3.

Пример 2.

     

Результаты: 

Блок-схема для примера 2 приведена на рис.2.

На рис.2 звездочкой () обозначены те переменные, адреса которых должны изменяться с шагом 2 в каждом цикле выполнения программы. В начальном состоянии этим переменным назначаются адреса переменных . Шаг переадресации при индекс-адресации определяется содержимым регистра , значение которого в конце каждого цикла увеличивается на 2.

Блоки на схеме рис.2 изображены как будто в линейном порядке, что визуально совпадает с внешним видом машинной программы, но на самом деле они выполняются не в таком порядке. Блок 3 передает управление на вычислительный блок 6, если  , в противном случае выполняется следующий блок 4, который в свою очередь передает управление на вычислительный блок 7, если  . Если же , то выполняется следующий вычислительный блок  (блок 8). После каждого вычислительного блока управление передается на блок 8, который записывает полученный результат в ячейку  .

Программная реализация примера 2 в условных кодах имеет следующий вид:

k+0   Load  00 00     0   0 -> R0

  2   St    00 00   < счетчик > 0 -> < счетчик >

 Load  10 01     k+28  подготовка команды

 St    00 01     k+100   перехода k+28

 Load  10 01     k+32  подготовка команды

k+10   St    00 01     k+102  перехода k+32

 12   Load  10 01     k+38  подготовка команды

14   St    00 01     k+104  перехода k+38

 16   Load  10 01     k+42  подготовка команды

 18   St    00 01     k+106  перехода k+42

k+20   Load  10 01     k+62  подготовка команды

 22   St    00 01     k+108  перехода k+62

 24   Load  11 10   < x*1 >   xi -> R2

 26   Cmp   10 10     6   (R2) <=> 6? 

 Jmp   10 10     k+100  УП при xi>= 6 на k+40

k+30   Cmp   00 10   < -6 >  (R2) <=> -6?

 Jmp   11 10     k+102  УП при xi<=-6 на k+44

 34   Sub   00 01   < a >  xi –a -> R2

 36   Mul   00 01   < a >  a(xi –a) -> R2

 Jmp   11 11     k+104  БП на k+50

k+40   Add   10 10     1   xi + 1 -> R2

 42   Jmp   11 11     k+106  БП на k+50

 Mul   11 10   < x*i >  xi * xi -> R2

 Mul   11 10   < x*i >  xi * xi2 -> R2

 Add   00 10   < a >  xi3 + a -> R2

k+50   St    11 10   < y*i >  yi -> < yi >

 52   Add   10 10     2   (R0) + 2 -> R0

 54   Load  00 01  < счетчик > счетчик-> R1 

 56   Add   10 01     1   (R1) + 1 -> R1

 58   St    00 01  < счетчик > R1 -> < счетчик > 

k+60   Cmp   10 00     5      счетчик <=> 5?

62   Jmp   10 00     k+108  повторение цикла с k+24

 64   Halt     останов 

 66   a = 5

 68   x1 = 3

k+70   x2 = -3

 72   x3 = 10

 x4 = -6

 76   x5 = 20 

 78   y1 

k+80   y2 

 y3 

 y4

   y5  

  счетчик

Преобразование двоичной записи машинной программы в заданную систему счисления и формирование входного текстового файла выполняются таким же образом, как и в примере 1.

Пример 3.

В примерах 1 и 2 проверена работа команд  Halt, Load, St, Add, Sub, Mul, Div, Cmp, Jump, а также все виды адресации. Остались непроверенными команды  And, Or, Xor, Shl, Shr, Call и Ret. В связи с этим в примере 3 будет реализовано обращение к подпрограмме, в работе которой используются логические команды и команды сдвига.

В подпрограмме будет вычисляться следующее выражение:

В основной программе будет реализовано двукратное обращение к подпрограмме. При первом обращении на место формальных параметров a и b будут переданы значения переменных a1 и b1, при втором обращениизначения  а2 и b2. Аналогично выходное значение y, получаемое в подпрограмме, будет присвоено соответственно переменным  y1 и y2.

k+ 0   Load  00 01   < a1 >

 St    00 01   < a >

 Load  00 01   < b1 >

6   St    00 01   < b >

  8   Call  00 03   k+30     { обращение к подпрограмме}

k+10   Load  00 01   < y .

 St    00 01   < y1 >

k+14   Load  00 01   < AM >

 St    00 01   < a >

 Load  00 01   < b2 >

k+20   St    00 01   < b >

 22   Call  00 03   k+30     { обращение к подпрограмме }

24   Load  00 01   < y .

 St    00 01   < y2 >

 Halt

k+30   Load  00 01   < a >    { начало подпрограммы }

32   And   00 01   < b >

 St    00 01    P1

 Load  00 01   < a >

 Shl   10 01     2

k+40   Or    00 01    P1

 St    00 01    P1

 Load  00 01   < b >

 Shr   10 01     3

 48   Xor   00 01    P1

k+50   St    00 01   < y >

52   Ret   00 03 00000000   { выход из подпрограммы }

54       a1 = 3355

56       b1 - 7767

58       а2 = 11435

k+60       b2 = 23876

62       y1

     y2

66       a

     b

k+70       y

72       P1

74       P2

Тестовые примеры фактически предназначены для для проверки корректности работы эмулятора. В связи с этим для каждого из них предварительно должны быть выполнены контрольные расчеты результатов, которые будут получены при безошибочной работе эмулятора.

Ниже приводится детальный поэтапный контрольный расчет для примера 3.

Первое обращение

a1 = 335510  = D1B16 ;   b1 = 776710 = 1E5716

a1  and b1:

 1101  0001  1011

0001  1110  0101  0111

0000  1100  0001  0011

a1 shl 2:

 0100  0110  1100

b1 shr 3:

0  0011  1100  1010 

(a1  and b1) or (a1 shl 2):

 1100  0001  0011

0011  0100  0110  1100

0011  1100  0111  1111

y1  =  (a1  and b1) or (a1 shl 2) xor (b1 shr 3):

0011  1100  0111  1111

0000  0011  1100  1010 

0011  1111  1000  0101

y1 = 3FB516 = 1616310

Второе обращение

a2 = 1143510  = AB16 ;  b2 = 2054810 = 504416

a2  and b2:

 1100  1010  1011

0101  0000  0100  0100

0000  0000  0000  0000

a2  shl 2:

 0000  0000  0000

b2  shr 3:

 1010  0000  1000 100

(a2 and b2) or (a2  shl 2):

 0000  0000  0000

y2 =  (a2 and b2) or (a2  shl 2) xor (b2 shr 3):

0000  0000  0000  0000

0000  1010  0000  1000

0000  1010  0000  1000

y2 = A0816  =  256810

3  РАЗРАБОТКА  ЭМУЛЯТОРА

3.1  Программные модели узлов  ЭВМ М1

Моделируемыми узлами ЭВМ М1 являются оперативная память, регистры и дешифратор. Им соответствуют в эмуляторе определенные переменные или массивы. Арифметико-логическое устройство АЛУ и сумматор адреса  SA  явным образом не моделируются: их функции выполняют соответствующие операторы программы.

Каждая ячейка памяти на машинном уровнеэто последовательность битовых элементов. Две смежные ячейки памяти ЭВМ М1 могут интерпретироваться в машине как команда, если их содержимое направлено в регистр команд RK, или как обрабатываемые данные, если это содержимое поступает в блок регистров R или в операционные регистры  OR1, OR2.  В последнем случае данные могут обрабатываться как числа, если на дешифратор поступил код арифметической команды, или как последовательности бит, если дешифрирована логическая команда.

В общем случае памятьэто массив битовых строк. Однако язык Турбо Паскаль не имеет в явном виде средств для изображения и обработки таких строк. В связи с этим могут быть предложены два варианта моделирования памяти.

В первом варианте ячейка памяти рассматривается как строка типа string[8], каждый байт которой может принимать значение ‘’или ‘’. Тогда модель памяти может быть представлена в следующем виде:

Type

  string8 = string[8];

MemoryAr = array[0..255] of string8;

Var

  Memory : MemoryAr;

Во втором варианте ячейка памяти изображается как множество из восьми элементов. Модель памяти для второго варианта:

Type

  set8 = set of 1..8;

MemoryAr = array[0..255] of set8;

Var

  Memory : MemoryAr;

Хотя внутренним представлением множества является битовая строка, но на уровне Паскаль-программы множество не может интерпретироваться как строка бит. Множество типа set8 лишь указывает, входят или не входят в его состав элементы  1 .. 8, что косвенным образом определяет значения 1 или 0 соответствующих разрядов ячейки памяти.

Регистры  RS, OR1, OR2, Res, RP и блок регистров R моделируются аналогично памяти (string или set).

Регистр команд RK, включающий в себя поля KOP, MA, NR и AM, целесообразно моделировать записью, компонентами которой являются модели битовых строк.

Модель регистра RK для первого варианта:

Type

  string2 = string[2];

string4 = string[4];

string8 = string[8];

RKType = record

    KOP : string4;

MA,NR : string2;

AM : string8

  end;

Var

  RK : RKType;

Модель регистра RK для второго варианта:

Type

  set2 = set of 1..2;

set4 = set of 1..4;

set8 = set of 1..8;

RKType = record

    KOP : set4;

MA,NR : set2;

AM : set8

  end;

Var

  RK : RKType;

Рассмотрим теперь вопрос о модели дешифратора. В общем случае дешифраторэто устройство, имеющее  входных и  выходных шин. Его функцией является активизация выходной шины, порядковый номер которой соответствует значению -разрядного двоичного числа на входе дешифратора. Моделью дешифратора является оператор Case.

Предположим, что код операции  RK.KOP  (строка или множество)  преобразован в программе в значение целочисленной переменной  NumKOP типа byte. Тогда модель дешифратора может иметь вид:

Case NumKOP of

  0 : ProcHalt;

1 : Load;

: Store;

: Add;

..................

: FromSubRoutine;

end;

Здесь  ProcHalt, Load, Store, Add,, FromSubRoutineпроцедуры, реализующие в эмуляторе машинные операции останова, загрузки операнда, сохранения операнда, сложения,, выхода из подпрограммы.

.2  Ввод и преобразование исходных данных

Исходными данными для эмулятора является машинная программа ЭВМ М1 и обрабатываемая этой машиной информация.

Машинную программу целесообразно компоновать в том виде, как это представлено в п.2.3 для ЭВМ М1. В этом случае как машинные команды, так и обрабатываемые этими командами данные располагаются в непрерывной последовательности ячеек памяти и могут быть введены эмулятором из одного текстового файла.

В зависимости от технического задания исходные данные изображаются в четверичной, восьмеричной или шестнадцатеричной системе счисления. Если в задании определена 16 с/с, то входной текстовый файл может иметь, например, следующий вид:

 20

 

 

 

 С

 B

 

 A

 612C

 212E

 

 FFE2

 EB

Здесь в первой строке текстового файла в 10 с/с записано значение пускового адреса машинной программы, в остальных строкахсодержимое ячеек памяти в 16 с/с.

Процедура ввода, входящая в состав эмулятора, должна прочесть содержимое входного файла как последовательность строк, преобразовать их в двоичный эквивалент и заполнить значениями 0 и 1 соответствующие элементы модели памяти Memory. Пример программы ввода для эмулятора ЭВМ М1 (информация в текстовом файле записана в 2 с/с, модель памятимассив множеств) приведен в прил.3.

В общем случае программа ввода может быть представлена следующим образом (в предположении, что содержимое одной строки текстового файла размещается в одной ячейке памяти):

Type

 string80 = string[80];

Var

  n,           { кол-во строк машинной программы}

Adr,            { адрес ячейки памяти }

SAK : byte;     { счетчик адреса команд }

S : string80; { строка входного файла }

InFile : text;  { входной текстовый файл }

Begin

 Reset(InFile);

Readln(InFile,SAK);

n:=1; Adr:=SAK;

While not Eof(InFile) do

Begin

     Inc(n);

Readln(InFile,S);

Удаление в строке S пробелов перед 

первой цифрой

Преобразование строки S в двоичный

эквивалент и запись его в элемент

Memory с индексом Adr

Inc(Adr);  { подготовка след.адреса }

   End;

 Close(InFile);

Преобразование строки S входного файла в битовую строку упрощается тем, что четверичная, восьмеричная и шестнадцатеричная системы счисления имеют основанием степень числа 2. Каждой цифре четверичной записи соответствуют две цифры двоичной записи, для восьмеричной записитри цифры (триада), для шестнадцатеричнойчетыре цифры (тетрада).

Предположим, что ячейка ЭВМ имеет длину 16 бит, а ее содержимое изображено в 16 с/с. Тогда соответствие между шестнадцатеричной и двоичной записями может быть представлено схемой, изображенной на рис.3.

Рис.3. Соответствие между двоичной и шестнадцатеричной записями

Следовательно, программа ввода должна переписать двоичное разложение первой шестнадцатеричной цифры строки S в первую тетраду двоичной записи, второй цифрыво вторую тетраду и т.д. Соответствие между шестнадцатеричной цифрой и ее двоичным эквивалентом в первом варианте модели памяти целесообразно представить в эмуляторе типизированной константой Ekv2.

Type  

  string4 = string[4];

Const

  Ekv16 = ‘ABCDEF’;

Ekv2 : array[1..16] of string4 =

(‘’,’’,’’,’’,’’,’’,

’’,’’,’’,’’,’’,’’,

’’,’’,’’,’’);

После ввода очередной строки S в цикле просматривают символы этой строки, с помощью функции Pos определяют порядковый номер k очередного символа и его двоичный эквивалент из типизированного массива Ekv2:

Var

  i,k : byte;

ch : char;

Begin

  For i:=1 to 4 do

Begin

      ch:=S[i]; k:=Pos(ch,Ekv16);

Перенос k-го элемента массива Ekv2

в i-ую тетраду ячейки Memory с 

индексом Adr

    End;

При использовании восьмеричной системы счисления для изображения 16-разрядной двоичной строки следует иметь в виду, что поскольку разделение двоичной последовательности на триады производится справа налево, то первая восьмеричная цифра может иметь только значение 0 или 1 и ей соответствует один, а не три бита двоичной строки.

При использовании второго варианта модели памяти преобразование входных строк в двоичный эквивалент имеет аналогичный характер.

.3. Прямое и обратное преобразования строки или множества в число

Операнды, поступающие в АЛУ из ячеек памяти, представлены в виде строки или в виде множества. При выполнении над ними арифметических операций необходимо предварительно получить численные значения этих операндов, т.е выполнить преобразование строки в число или множества в число. После выполнения арифметической операции ее результат перед записью в память требуется преобразовать в двоичный эквивалент.

Преобразования множества в число и числа в множество представлены в эмуляторе ЭВМ М1 в виде процедур  FromSetToNumber и FromNumberToSet (см. прил. 3).

Рассмотрим выполнение указанных преобразований для строк.

В строке S символами ‘’и ‘’изображается двоичное число. Будем считать это число положительным.

Пусть нам требуется преобразовать n-разрядную строку S, содержащую двоичные цифры числа, в численное значение целой переменной P. Учитывая, что первый разряд строки Sэто знак числа, а значащими являются (n-1) цифр, эту строку можно представить в виде

,

где   - символы строки S  (‘’или ‘’).

Такое представление строки фактически и является схемой ее преобразования в число. Вычисление записанного выше полинома следует проводить по схеме Горнера:

,

где   - двоичные цифры 0 или 1 (цифра , определяющая знак числа, равна нулю).

Преобразование числа Р в n-разрядную строку S выполняется в обратном порядке по схеме:

;    ;

;    ;

……………………………………….

;    ;

Поскольку  , то последний оператор эквивалентен следующему:

Отрицательные числа представлены в строке S в дополнительном коде. Следовательно, при переводе   требуется в случае необходимости выполнить преобразование дополнительного кода в прямой код, а при преобразовании   –преобразование прямого кода в дополнительный.

Как известно, для получения дополнительного кода отрицательного двоичного числа требуется инверсировать его цифры, а затем добавить единицу к младшему разряду полученного числа. При переходе от дополнительного кода отрицательного числа к его прямому коду из дополнительного кода предварительно вычитается единица. Поскольку арифметические операции над строками невозможны, то эти действия должны производиться по отношению к численным представлениям содержимого преобразуемых строк. Возможные варианты преобразования   и  представлены в приведенных ниже процедурах по отношению к 16-разрядным двоичным числам. При рассмотрении указанных процедур следует учитывать, что первый байт строкиэто знак двоичного числа.

Procedure FromStringToNumber(Operand:string16;

Var Number:integer);

{ Преобразование строки в число }

Var   i : byte;

Cond : boolean;  { признак отрицательного числа }

Begin

 Cond:=false;

If Operand[1]=’’then

Begin

     Cond:=true;

For i:=1 to 16 do        { инверсирование }

If Operand[i]=’’then { цифр отрицатель-}

Operand[i]:=’’{ ного двоичного }

Else                   { числа }

Operand[i]:=’’;

   End;           

 Number:=0;                  { получение числен- }

For i:=2 to 16 do           { ного значения по }

Begin                     { схеме Горнера }

Number:=2*Number;

If Operand[i]=’’then

       Inc(Number);

End;

 If Cond then             { добавление 1, если }

Begin                  { был преобразован }

Inc(Number);         { дополнительный код, }

Number:=-Number      { и изменение знака }

End;                   { числа }

End { FromStringToNumber };

Procedure FromNumberToString(Number:integer;

Var Operand:string16);

{ Преобразование числа в строку }

Var   i : byte;

k,

Divisor : integer; { делитель }

Cond : boolean;    { признак отрицательного числа }

Begin

 Cond:=false;

If Number<0 then

   Begin              { получение положитель- }

Cond:=true;           { ного числа и вычи- }

Number:=-Number;      { тание из него }

Dec(Number)           { единицы }

   End;

 Divisor:=16384;       { делитель =  (n=16) }

Operand:=’’;

For i:=2 to 16 do           { последовательное }

Begin                     { формирование }

k:=Number div Divisor;  { двоичных цифр }

If k>0 then             { числа }

Operand:=Operand+’’

Else

       Operand:=Operand+’’;

Number:=Number mod Divisor;

Divisor:=Divisor shr 1;

   End;

 If Cond then                { инверсирование }

For i:=1 to 16 do         { цифр отрицатель- }

If Operand[i]=’’then  { ного числа  (по- }

Operand[i]:=’’       { лучение дополни- }

     Else                    { тельного кода) }

Operand[i]:=’’;

End { FromStringToNumber };

3.4. Индикация переполнения с фиксированной запятой

Арифметические операции, входящие в систему команд учебной ЭВМ, в эмуляторе выполняются в конечном счете над переменными типа integer или longint: integer, если длина разрядной сетки ЭВМ меньше или равна 16 двоичным разрядам, и longint в противном случае.

При выполнении Паскаль-программы в ПЭВМ переполнение целочисленных переменных не индицируется, т.е. такая ситуация не приводит к прерыванию программы, в том числе при включенной директиве компилятора R. Однако переменная в этом случае получает неправильное значение, что в дальнейшем неизбежно приводит к ошибкам в работе программы.

Рассмотрим следующий фрагмент программы:

{R+}

Var  k,l,m,n,s : integer;

p,q : longint;

Begin

 k:=25000; l:=25000;

m:=k+l; n:=k*l;

p:=k+l;

q:=k; q:=q+l;

Writeln(‘m = ‘,m,n = ‘,n);

Writeln(‘p = ‘,p,q = ‘.q);

s:=q;

Writeln(‘s = ‘,s);

В результате работы программы будет отпечатано:

m = -15536   n = -16832

P = -15536   q = 50000

 S = -15536   

В выражении  k+l оба операнда имеют тип integer, поэтому и значение выражения будет иметь тот же тип. Это объясняет, в частности, почему переменная р типа longint получила неправильное значение.

В выражении  q+l  один из операндов имеет тип integer, второйтип longint. Перед вычислением выражения значение переменной l преобразуется к старшему типу, т.е. типу longint. Вследствие этого переменной q присваивается правильное значение, равное 50000.

При вычислении выражений  k+l  и  k*l  директива  R+  не индицирует выход значения выражения за пределы границ, допустимых для типа integer  (-32768 .. 32767). Такая индикация (прерывание 201  Range check error) имеет место лишь при выполнении оператора  s := q,  когда производится попытка присвоить переменной s значение вне допустимого диапазона.

В системах команд учебных ЭВМ предусмотрено присваивание регистру признаков RP значения, индицирующего переполнение с фиксированной запятой (ПФЗ). Для того, чтобы эмулятор определил наличие ПФЗ, в процедурах выполнения арифметических операций следует предварительно преобразовать целочисленные операнды к типу real, выполнить соответствующую операцию и сравнить полученный результат с граничными значениями, соответствующими разрядной сетке ЭВМ.

Пусть учебная ЭВМ имеет разрядную сетку, состоящую из 26 двоичных разрядов. Поскольку один разряд при этом отводится для знака числа, то допустимый диапазон изменения целочисленной переменной в этом случае равен

Обозначим значение  33554431  как константу  MaxNumber:

Const  MaxNumber = 33554431;

Тогда индикация ПФЗ в процедуре сложения может быть выполнена следующим образом:

Var  Operand1,Operand2,Res : longint;

a,b,c : real;

Begin

..............................

a:=Operand1; b:=Operand2;

c:=a+b;

If (c<-MaxNumber-1) or (c>MaxNumber) then ...

Аналогичные проверки производятся также в процедурах вычитания и умножения.

В процедуре деления ПФЗ не может иметь места, а для индикации деления на нуль должна производиться предварительная проверка целочисленного делителя на равенство его нулю.

.5. Режимы работы эмулятора

Режимы работы эмулятора определяются естественными требованиями, которые возникают при отладке машинной программы.

Является очевидным, что машинную программу гораздо труднее понимать, чем Паскаль-программу; в машинной программе также значительно больше вероятность появления ошибок (неправильный адрес или значение операнда, случайная замена 0 на 1 в машинной команде и т.п.). Поэтому при отладке машинной программы необходимо анализировать состояние функциональных узлов ЭВМ (память и регистры) фактически после выполнения каждой машинной команды.

Приведенные выше соображения требуют включения в состав эмулятора по крайней мере следующих режимов его работы:

  1.  ввод исходных данных (Input);
  2.  полное выполнение программы (Run);
  3.  шаговое выполнение программы (Step);
  4.  просмотр содержимого памяти  (Memory).

Выбор режима работы должен производиться путем передвижения строки-курсора по позициям основного меню.

В режиме Input производится ввод входного текстового файла, формирование значения пускового адреса и заполнение соответствующих ячеек оперативной памяти Memory.

Работа эмулятора может быть проверена путем решения нескольких тестовых примеров (для ЭВМ М1 в п.2.3 приведено три таких теста). Поэтому при проектировании режима Input необходимо предусмотреть ввод по запросу программы имени файла, содержащего требуемый тест.

В режиме Run выполняются все команды машинной программы вплоть до достижения команды останова.

В режиме Step после выполнения каждой очередной машинной команды на экране должно быть отображено состояние всех регистров машины. По отношению к ЭВМ М1это регистры SAK, RA, RS, RK, OR1, OR2, Res, RP, блок регистров R. Для регистров SAK и RA достаточно указать в рамке десятичные значения их содержимого, для RP представляется логичным вывести на экран его двоичное значение, для остальных регистров, кроме двоичного изображения их содержимого, целесообразно выводить на экран также соответствующее десятичное значение. Переход к выполнению следующей машинной команды должен осуществляться после нажатия клавиши Enter.

В режиме Memory должен быть организован на экране скроллинг содержимого оперативной памяти ЭВМ (адрес ячейки,  двоичное и десятичное значение ее содержимого, а также значение в заданной по варианту системе счисления (4, 8 или 16 с/с). Для улучшения сервиса работы пользователя рекомендуется предусмотреть ввод по запросу эмулятора значений начального и конечного адресов просматриваемой области памяти.

Указанные режимы являются обязательными при проектировании эмулятора любой учебной ЭВМ. Кроме них в техническое задание могут быть включены также дополнительные режимы, например:

  1.  печать заданной области памяти на принтере  (PrintMem);
  2.  печать на принтере в режиме Step содержимого регистров (PrintStep);
  3.  перевод числа  ,   (Trans10_16, Trans10_4, Trans10_8) ;
  4.  перевод числа  ,   (Trans16_10, Trans4_10, Trans8_10);
  5.  контроль корректности исходных данных (Check) и др.

Остановимся несколько подробнее на режиме Check, в котором должна производиться синтаксическая проверка машинной программы.

Возможные синтаксические ошибки в машинной программе полностью определяются структурой ЭВМ и составом ее системы команд. В частности, по отношению к ЭВМ М1 должны быть выполнены следующие требования:

  1.  в машинной программе обязательно должна быть команда останова;
  2.  пусковой адрес должен быть четным;
  3.  значение пускового адреса должно быть в диапазоне  0 .. 255;
  4.  адреса операндов должны быть четными;
  5.  для команды перехода допустима лишь косвенная адресация;
  6.  для команд  St, Call и Ret не должна использоваться непосредственная адресация  и др.

При вводе строк исходного текстового файла должны быть предусмотрены проверки, связанные с представлением машинной программы в заданной системе счисления. Такими проверками могут быть:

  1.  наличие на диске заданного текстового файла;
  2.  размер входного файла (не является ли он пустым);
  3.  длина строки текстового файла (количество цифр);
  4.  отсутствие недопустимых символов в строке (например, символа5 для 4 с/с или символа  “K”  для 16 с/с и т.п.).

При обнаружении синтаксических ошибок на экран должно выдаваться сообщение о месте и типе ошибки, после чего работа эмулятора должна прерываться.

.6. Формирование меню

Наиболее простым способом организации меню является выбор позиции меню с помощью оператора Case.

Const

 St : array[1..4] of string[32] =

(‘П о з и ц и я  1,П о з и ц и я  2,

П о з и ц и я  3,П о з и ц и я  4);

Var  i,Switch : byte;

Begin

 ClrScr;

For i:=1 to 4 do

Begin

     GotoXY(2*i+10,20);

Write(i:2,’‘,St[i]);

   End;

 GotoXY(20,3);

Write(‘Укажите номер позиции меню);

Readln(Switch);

Case Switch of

: Proc1;

: Proc2;

: Proc3;

4 : Proc4;

 end;

Позиции  1 .. 4  –это наименования режимов работы эмулятора;

Оператор Case формирует обращение к одной из процедур  Proc1 ..  Proc4  в зависимости от введенного значения переменной Switch.

Более совершенным является формирование такого меню, в котором строка-курсор указывает на выбираемую позицию путем ее цветового выделения. При этом клавиши перемещения курсора обеспечивают видимое передвижение по позициям меню, а активизация выбранной позиции производится нажатием заранее определенной управляющей клавиши (например, Enter или Tab). Пример формирования такого меню приведен в тексте эмулятора М1 (прил.3).

При формировании меню в эмуляторе ЭВМ М1 используются процедуры MakeMenu (модуль Emulat), MoveCursor, Frame и InsertColorString (модуль BasUnit).

В процедуре MakeMenu вначале формируется на экране рамка путем обращения к процедуре Frame.

Рамка, которую рисует на экране процедура Frame, может быть окаймлена одинарной  (Line = 1), двойной  (Line = 2) или широкой  (Line = 3) линией. Цвет рамки и фоновый цвет ее внутренней области определяются значением формального параметра  Color, которому в данном случае при обращении присваивается значение  LightGrayBlack (фонсветлосерый, цвет символачерный).

После отработки процедуры Frame на экране печатаются строки массива St, определяющие содержание позиций меню. Начальная активизация одной из позиций обеспечивается заданием значений переменным  CurrRow (номер текущей строки экрана) и CurrCol (номер текущего столбца экрана), после чего процедура  InsertColorString  подсвечивает выделенную позицию цветом BlueYellow (фонсиний, символжелтый).

Передвижение строки-курсора по позициям меню осуществляется процедурой MoveCursor, с помощью которой можно формировать как вертикальное, так и горизонтальное меню путем задания соответствующих значений ее формальным параметрам. Выход из процедуры MoveCursor производится при нажатии клавиши Enter или клавиши Tab. При этом текущее значение переменной CurrRow указывает положение активизированной позиции меню, после чего с помощью оператора Case осуществляется обращение к процедуре, соответствующей этой позиции.

3.7. Организация скроллинга

При вертикальном сдвиге текстового экрана вверх строки  2 .. 25  переписываются в строки  1 .. 24, а в строку 25 вводятся данные из оперативной памяти (содержимое строки типа string[80]). Сдвиг вниз осуществляется аналогично.

Вертикальный сдвиг экрана называют также скроллингом (scrollрулон, свиток).

Пусть для заполнения строки экрана в программе используется переменная BufRow типа ScreenRowArray (см.описание типов в модуле DesUnit, прил.3).

Вертикальный сдвиг вверх:

Procedure ScreenToUp;

Var  i : byte;

Begin

 For i:=1 to 24 do

   Screen[i]:=Screen[i+1];

Screen[25]:=BufRow;

End { ScreenToUp };

Вертикальный сдвиг вниз:

Procedure ScreenToDown;

Var  i : byte;

Begin

 For i:=25 downto 2 do

   Screen[i]:=Screen[i-1];

Screen[1]:=BufRow;

End { ScreenToDown };

Аналогичным образом можно организовать скроллинг области экрана, ограниченной строками  Row1, Row2  и столбцами  Col1, Col2.

Для организации скроллинга можно использовать также процедуры InsLine и DelLine. Эти процедуры позволяют «прокручивать» часть текстового окна или весь экран вверх и вниз. InsLine вставляет пустую строку на место той, где находится в текущий момент курсор. Все нижние строки, начиная с нее, смещаются вниз на одну строку. Самая нижняя строка уйдет за нижнее поле окна и исчезнет.

Процедура DelLine  удаляет строку, в которой находится курсор, подтягивая на ее место все нижестоящие строки. При этом освобождается самая нижняя строка экрана.

Все строки, которые освобождаются при работе процедур  InsLine и DelLine, закрашиваются текущим цветом фона.

Пример программы, выполняющей скроллинг текста в окне экрана с помощью процедур  InsLine и DelLine, приведен в прил.4.

.8. Структура эмулятора

Программа эмулятора должна иметь модульную структуру (в противном случае общий объем ее объектного кода не может превышать 64 Кбайт).

Количество модулей и их иерархия в языке Турбо Паскаль не регламентируются. Требуется соблюдать лишь одно требование: в предложениях Uses не должно создаваться перекрестных связей между модулями (например, если в модуле  RecUnit  стоит фраза  “Uses Crt, Dos, TabUnit, VenUnit, а в модуле  TabUnitфразаUses  Crt, RecUnit, LabUnit”).

При выполнении курсовой работы по проектированию эмулятора целесообразно воспользоваться приведенными ниже рекомендациями.

) Имя модуля в соответствии с требованиями языка Турбо Паскаль должно совпадать с именем файла, который содержит данный модуль. В связи с этим длина имени модуля не может превышать 8 символов. Рекомендуется в качестве последних четырех символов в имени модуля использовать слово Unit (например, DesUnit, BasUnit  и т.п.). Это позволяет легко отличать в каталоге файлы с именами модулей.

) Все глобальные объявления констант, типов и переменных сосредоточить в одном модуле, присвоив ему имя DesUnit (от слова Descriptionописание).

) Служебные (базовые) процедуры и функции, используемые в нескольких модулях, сосредоточить в модуле с именем BasUnit. Если при разработке эмулятора используется значительное количество процедур по управлению текстовым режимом экрана, то их целесообразно записать в отдельном модуле (например, с именем ScreUnit; screenэкран).

) В основную программу  ”Program Emulatвключить формирование заставки, формирование главного меню, установку в начальное состояние (очистку) узлов эмулируемой ЭВМ и выбор режима работы эмулятора.

) В одном или в двух модулях разместить процедуры, реализующие режимы работы эмулятора (например, в модуле RegUnit; regimeрежим).

) В заставке указать название программы, учебную группу, фамилию и инициалы студента, название учебной ЭВМ. После вывода на экран заставки должна быть приостановлена работа программы до нажатия клавиши Enter.

) Все процедуры, непосредственно эмулирующие машинные команды, рекомендуется разместить в отдельном модуле (например, в модуле InsUnit; instructionкоманда).

В процессе отладки эмулятора рекомендуется перед именем каждого модуля установить директиву компилятора {$R+}, которая включает проверку корректности присваивания ординальным переменным новых значений, в том числе проверку выхода индекса за границу массива или строки.

Примером использования модулей в программной организации эмулятора является приведенный в приложении 3 эмулятор ЭВМ М1.

.9. Стиль программирования

Основным принципом в проектировании программ является следующий: программа составляется в первую очередь для человека, а не для машины. Промышленные программные комплексы разрабатывает группа специалистов. В процессе его эксплуатации неизбежно возникает необходимость коррекции и модернизации комплекса, что будет требовать от разработчиков читать и изменять как собственные программы, так и программы их коллег. В связи с этим в текстах разрабатываемых программ обязательно должны содержаться средства, облегчающие понимание программы и улучшающие ее читабельность.

Специальных стандартов на тексты программ не существует. Тем не менее профессиональные программисты в написании текста программы придерживаются определенных правил, направленных на соблюдение приведенного выше принципа программирования.

При написании курсовой работы по проектированию эмулятора обязательным по отношению к тексту программы является выполнение указанных ниже требований.

) Заголовки модулей и его секций, заголовки программы и каждого ее раздела начинать с первой позиции строки.

) После заголовка модуля (Unit) указывать в комментарии основное назначение входящих в модуль процедур и функций.

) После заголовка процедуры или функции приводить в комментарии краткое описание выполняемой ею работы.

) Длинные тексты программы разделять комментариями на фрагменты. В комментарии кратко описывать работу фрагмента.

) После объявления имени переменной в комментарии указывать назначение переменной.

) Процедуры и функции отделять друг от друга пунктирной линией, заключенной в комментарий.

) После слова End, завершающего блок процедуры или функции, в комментарии записывать имя данной процедуры или функции.

) В качестве символов комментария использовать только фигурные скобки.

) Каждое слово Begin начинать с новой строки.

) Каждое слово End записывать с новой строки строго с той позиции, с которой начинается относящееся к нему слово Begin, Case или Record.

11) Текст программы между словами  Begin и End, Case и End, Record и End должен быть сдвинут на один отступ вправо. Отступ равен двум позициям строки.

) Текст программы после слов  do, then, else  должен начинаться с новой строки, сдвинутой на один отступ вправо.

) Каждое слово Else должно быть расположено под тем словом If, к которому оно относится.

) Разделы описаний, как правило, нужно располагать в том порядке, который предусмотрен стандартным языком Паскаль: Label, Const, Type, Var, описание процедур и функций.

) Имена всех переменных, кроме параметров циклов и индексов элементов массивов и строк, записывать с прописной буквы. Это относится как к простым, так и к составным переменным (массивы, записи, множества и др.).

) Имена переменных в программе в общем случае не должны отличаться от обозначений, принятых в исходной постановке задачи. Например, было бы недопустимым обозначить в программе эмулятора регистр команд именем Zz, даже снабдив его комментарием, что это имя  является обозначение регистра команд.

) Отдельные части имени, состоящего из нескольких слов, нужно выделять прописными буквами (например, FromSetToNumber).

) Оператор Goto разрешается применять в программе в двух случаях:

а) для принудительного выхода из цикла;

б) для перехода к удаленному фрагменту программы.

Совершенно недопустимо использовать оператор Goto для перехода снизу вверх в программе.

Если оператор Goto производит переход на конец процедуры или функции, то его целесообразно заменить процедурой Exit. Таким же образом для принудительного выхода из цикла оператор Goto можно заменить процедурой Break, а для перехода на конец циклапроцедурой  Continue.

19) Длина строки программы не должна превышать 68 символов (для печати текста программы редактором компилятора Паскаль на бумаге формата А4).

) В программе вместо значений констант использовать, как правило, имена констант.

) В разделе описания переменных использовать имена типов, а не описания типов. Например, вместо описания

Var

  A : array[1..100] of string[40];

целесообразно использовать описание

Const  Nmax = 100;

Type  

   string40 = string[40];

Ar = array[1..Nmax] of string40;

Var

   A : Ar;

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

.10. Описание эмулятора ЭВМ М1

Эмулятор ЭВМ М1 включает в себя основную программу Emulat и четыре модуля: DesUnit, BasUnit, InsUnit и RegUnit.

Модуль DesUnit содержит глобальные описания констант, типов и переменных; модуль BasUnitслужебные процедуры и функции, используемые в других модулях; модуль InsUnitпроцедуры реализации машинных команд; модуль RegUnitпроцедуры реализации режимов работы эмулятора. Основная программа управляет работой эмулятора.

В начальном фрагменте основной программы производится очистка памяти Memory и регистров эмулируемой ЭВМ. После этого с помощью меню, формируемого процедурой MakeMenu, осуществляется выбор режима работы эмулятора (описание процедур формирования меню приведено в п.3.6).

В эмуляторе ЭВМ М1 предусмотрены следующие режимы работы:

  •  ввод исходных данных;
  •  полное выполнение машинной программы;
  •  шаговое выполнение программы;
  •  вывод области памяти;
  •  перевод числа  ;
  •  выход из меню.

Ввод исходных данных осуществляется процедурой InputModul. Здесь из первой строки файла FileModul вводится значение пускового адреса SAK, после чего последовательно вводятся остальные строки файла вплоть до его исчерпания. Содержимое очередной строки файла FileModul, содержащее два машинных слова в двоичной системе счисления, вводится в строковую переменную S1, после чего из S1 выделяется значащая часть строки, запоминаемая в переменной S2. По содержимому строки S2 дважды формируется буферная переменная Slovo (множество типа set8) и записывается в элементы массива Memory с индексами  k и k+1. Начальное значение индекса  k  равно значению  SAK, после ввода каждой очередной строки файла значение переменной k увеличивается на 2.

Режим полного выполнения машинной программы реализуется процедурой Run. Здесь в цикле While последовательно просматриваются пары ячеек памяти Memory, начиная с адреса SAK. Управление циклом осуществляет булевская переменная CondExec, принимающая значение false при достижении команды останова (код операции 0000).

Каждая пара машинных слов заполняет поля KOP, MA, NR и AM регистра команд RK. Поля KOP и NR преобразуются в числовое значение переменных Switch и NumReg. После этого по значению переменной Switch с помощью оператора Case производится обращение к процедуре, которая реализует машинную команду, соответствующую данному коду операции KOP.

В модуле InsUnit, кроме процедур реализации машинных команд, имеются также процедуры формирования исполнительного адреса ExecAddress и формирования содержимого операционного регистра OR2. Указанные процедуры анализируют значение модификатора адреса NR, формируют исполнительный адрес операнда и его значение, записываемое в операционный регистр OR2. При работе процедур реализации машинных команд и формирования машинного адреса выполняется в случае необходимости преобразование множества в число и числа в множество, что осуществляется процедурами FromSetToNumber и FromNumberToSet.

В режиме шагового выполнения программы Step после исполнения каждой машинной команды на экране отображается содержимое регистров ЭВМ М1. Переход к выполнению следующей команды машинной программы производится после нажатия клавиши Enter.

В режимеВывод области памятиосуществляется скроллинг области памяти Memory. Содержимое каждых двух ячеек памяти отображается  в 2, 16 и 10 с/с.

В режиме перевода из десятичной в шестнадцатеричную системы счисления осуществляется указанный перевод для числа, задаваемого пользователем с клавиатуры ЭВМ.

Примечание. В прил.3 из методических соображений, а также для сокращения общего объема печатаемого текста приведены лишь основные фрагменты эмулятора ЭВМ М1.

.11  Рекомендации по разработке эмулятора

Разработку большой программы всегда выполняют путем постепенного наращивания еескелета, последовательно добавляя к ней новые процедуры и модули, расширяющие функции и улучшающие эстетическое оформление проектируемой программы. По отношению к программе-эмулятору рекомендуется выполнять ее разработку в следующей последовательности.

1. Сформировать файл исходных данных, разместив в нем наиболее простой тест (например, y = a + b).

. Создать модули DesUnit, BasUnit, RegUnit и модуль основной программы Emulat.

В модуле DesUnit разместить описания констант, типов и переменных, обеспечивающих работу с оперативной памятью Memory и исходным текстовым файлом.

В модуль BasUnit включить процедуры WaitEnter, PrintString, PrintKeyAndWaitEnter (эти процедуры используются для приостановки решения при отладке программы) и функцию Space (используется при вводе и обработке входного файла).

В модуль RegUnit записать процедуру ввода исходных данных, их преобразования и занесения в ячейки памяти Memory.

Начальные функции основной программы Emulat:

  •   установка ячеек памяти Memory в нулевое состояние;
  •   обращение к процедуре ввода исходных данных.

Для отладки процедуры ввода исходных данных и проверки корректности заполнения памяти Memory можно использовать процедуру, аналогичную процедуре WriteMemory (модуль BasUnit эмулятора ЭВМ М1).

. Добавить в модуль DesUnit объявления регистров ЭВМ, а в начальный фрагмент основной программыоператоры их обнуления. В модуль BasUnit включить процедуры прямого и обратного преобразования строки (множества) в число, проверить работу этих процедур.

. Добавить в основную программу простое меню (см.п.3.5), заполнив в нем две позиции –“Ввод исходных данныхиПолное выполнение программы, в остальных позициях меню поставить пустые операторы.

. Сформировать модуль InsUnit, включив в него процедуры реализации команд, необходимых для выполнения простого теста.

Разработать процедуру Run, осуществляющую перебор команд машинной программы и обращение к процедурам их реализации; включить эти процедуры в состав модуля RegUnit.

Віполнить отладку разработанных процедур. Для вывода на экран содержимого регистров ЭВМ можно использовать процедуру, аналогичную процедуре WriteRegisters (модуль BasUnit эмулятора ЭВМ М1).

Разработать и отладить процедуры реализации всех оставшихся машинных команд.

. Заменить в основной программе простое меню более совершенным типом меню.

. Разработать и отладить процедуры шагового выполнения программы (с отображением на экране содержимого регистров ЭВМ) и скроллинга содержимого памяти Memory.

. Модернизировать процедуру ввода исходных данных, включив в нее формирование по запросу имени входного файла.

. Разработать и отладить процедуру формирования заставки эмулятора.

. Разработать и отладить процедуры реализации дополнительных режимов работы эмулятора.

. Произвести тестирование работы эмулятора.

.12  Содержание пояснительной записки

Пояснительная записка к курсовой работе должна содержать в себе следующие разделы.

. Введение. Во введении следует определить понятие эмуляции, описать области применения эмуляторов, указать цель выполнения курсовой работы.

. Описание учебной ЭВМ. Изобразить структурную схему ЭВМ, описать архитектуру машины, привести систему команд и описать последовательность их выполнения.

. Программирование в кодах учебной ЭВМ. Привести используемые в дальнейшем мнемонические коды операций и других элементов машинной команды, для каждого теста написать программу в условных кодах (с комментариями), программу на машинном языке и содержимое исходного файла в заданной системе счисления, кратко описать программную реализацию тестов.

. Описание эмулятора. Описать структуру, перечень и назначение программных модулей, режимы работы эмулятора, программную реализацию каждого режима, привести количественные характеристики эмулятора.

. Заключение. В заключении должны быть кратко подведены итоги работы: что именно выполнено в курсовой работе, какой язык программирования и операционная система использованы при разработке программного продукта, основные характеристики программы (количество модулей, режимы работы, объем исходного и объектного кодов программы, результаты тестирования и пр.).

. Список использованных источников.

. Приложение 1. Текст эмулятора.

. Приложение 2. Результаты тестирования.

Л И Т Е Р А Т У Р А

. Поляков Д.Б., Круглов И.Ю. Программирование в среде Турбо Паскаль.М.: Изд-во МАИ, 1992.с. 

. Фаронов В.В. Турбо Паскаль 7.0. Начальный курс.М.:Нолидж, 1997.с.

. Фаронов В.В. Турбо Паскаль 7.0. Практика программирования.М.:Нолидж, 1997.с.

. Немнюгин С.А. Turbo Pascal.СПб:Питер, 2001.с.

. Немнюгин С.А.  Turbo Pascal:  практикум.СПб:Питер, 2001.с.

. Назаренко В.И. Основы программирования на языке Турбо Паскаль (на дискете).Донецк, ДонНТУ, 2005.