Текст
                    Р.Сибеста
Структурное программирование
на языке ассемблера ЭВМ
Структурное
программирование
на языке
ассемблера ЭВМ
И4Х-11
Издательство «МИР»


Структурное программирование на языке ассемблера ЭВМ И4Х11
VAX II STRUCTURED ASSEMBLY LANGUAGE PROGRAMMING Robert W. Sebesta University of Colorado at Colorado Springs The Benjatnin/Cummings Publishing Company, Inc., Menlo Park, California, USA, 1984
РСибеста Структурное программирование на языке ассемблера ЭВМ кЯХ-П Перевод с английского канд. техн, наук В. И. ГУРЕВИЧА, канд. физ.-мат. наук Ю. Н. ЖЕЖЕЛЯ, М. Л. МИРИМОВА под редакцией канд. техн, наук В. К. ПОТОЦКОГО Москва «Мир» 1988
ББК 32.973—01 С 34 УДК 681.3 Сибеста Р. С 34 Структурное программирование на языке ассемблера ЭВМ VAX-11: Пер. с англ. — М.: Мир, 1988. — 536 с., ил. В книге американского специалиста излагаются основы программирования па языке ассемблера ЭВМ VAX-11, которая отличается от PDP-11 более развитой архитектурой, возможностью обработки 32- и 64-разрядных слов, виртуальной па- мятью до 4 Гбайт и высоким быстродействием. Пользуясь данной книгой, можно достаточно быстро освоить процедуру составления программ для создаваемых в нашей стране перспективных машин серии СМ ЭВМ. Для специалистов, работающих в области разработки программного и ин- формационного обеспечения, а также студентов, изучающих вычислительную тех- нику. С 24 198-88, ч. 1 ББК 32.973-01 Редакция литературы по информатике и робототехнике © 1984 by The Benjamin/Cummings Publishing Company, Inc. © перевод на русский язык, «Мир», 1988
ПРЕДИСЛОВИЕ РЕДАКТОРА ПЕРЕВОДА В настоящее время роль средств вычислительной техники в на- родном хозяйстве и повседневной жизни человека столь значи- тельна, что нет необходимости убеждать читателя в целесооб- разности получения хорошей подготовки в области эксплуатации современных ЭВМ и программирования. Еще более актуальным представляется приобретение таких знаний для системных про- граммистов, т. е. тех, кто разрабатывает и эксплуатирует сред- ства программного обеспечения ЭВМ. Машинно-ориентированные языки являются основным рабо- чим инструментом системного программиста. Начинающему про- граммисту, стремящемуся достичь высокой квалификации в об- ласти системного программирования, важно удачно выбрать в качестве «предмета» изучения такой машинно-ориентированный язык, который наиболее полно раскрывал бы потенциальные возможности архитектуры основных моделей современных вы- числительных машин от супер- до мини- и микроЭВМ. Хорошо известно, что «первый» язык программирования во многом определяет в дальнейшем «вкус» и «неприязнь» программиста к тем или иным средствам программирования. Машинно-ориен- тированные языки ограниченных возможностей «сковывают» программиста, в то время как языки, которым присуще большое разнообразие программных средств, способствуют формирова- нию у начинающего системного программиста рационального подхода к проблемам технологии программирования. Язык ассемблера супер-мини-ЭВМ VAX-11 является приме- ром символического машинно-ориентированного языка значи- тельных потенциальных возможностей. Архитектура VAX-11 во многом подобна архитектуре большинства современных вычис- лительных машин и прежде всего широко распространенных мо- делей IBM-360, ЕС ЭВМ, PDP-11, СМ-4 и т. п. ЭВМ VAX-И — это высокопроизводительная вычислитель- ная система с мультипрограммированием и множественным до- ступом, имеющая 32-битовую архитектуру и располагающая операционной системой виртуальной памяти VAX/VMS. Техни- ческие средства VAX-11 обеспечивают режим совместимости с ЭВМ PDP-11, имеющей 16-битовую архитектуру. Мощный набор
6 Предисловие редактора перевода команд и богатство средств системы адресации VAX-11 делают изучение языка ассемблера этой вычислительной машины весь- ма непростым занятием, однако вознаграждающим изучающего универсальностью получаемых знаний. Предлагаемая читателю книга является учебным пособием по программированию на языке ассемблера VAX-11 и написана в соответствии с принятым в настоящее время так называемым структурным подходом к изложению материала. Во многом это автору удается, и уже на сравнительно ранних этапах изучения языка ассемблера в распоряжении читателя законченные рабо- тоспособные программные модули, что, безусловно, немало- важно и вселяет в него вполне оправданную уверенность в осу- ществлении поставленной цели — овладение принципами и тех- никой программирования на языке ассемблера мощной супер- мини-ЭВМ. Эти знания позволят сравнительно просто и легко освоить язык ассемблера и архитектуру большинства современ- ных вычислительных машин, включая и получающие массовое распространение персональные ЭВМ. Развитию современной вычислительной техники присуща ярко выраженная тенденция определенной «стандартизации» логической структуры, принципов построения операционных си- стем и средств программного обеспечения ЭВМ. Это объясняет интерес широких кругов советских читателей к издаваемой за рубежом литературе по вычислительной технике. Коллектив, ра- ботавший над переводом на русский язык и подготовкой к изда- нию данной книги, надеется, что она окажется весьма полезной для системных программистов и студентов высших учебных за- Ьедений, специализирующихся в области программного обеспе- чения ЭВМ. Перевод выполнен канд. физ.-мат. наук Ю. Н. Жежелем (гл. 1—4),) канд. техн, наук В. И. Гуревичем (гл. 5—12 и при- ложения), М. Л. Миримовым (гл. 13—15). Потоцкий В. К.
ПРЕДИСЛОВИЕ АВТОРА Тема книги Для желающих овладеть языком ассемблера вычислительной машины выбор супермини-ЭВМ серии VAX следует признать одним из наиболее удачных. Прежде всего нужно отметить, что архитектура VAX включает в свой состав многое из того, что присуще большинству других вычислительных машин и систем. В набор команд VAX входят многие команды, типичные для вы- числительных систем предыдущего поколения, таких, как PDP-11 и IBM-360. Поэтому для тех, кто знаком с языком ассемблера VAX, не представляет особого труда освоение программирова- ния на языке ассемблера упомянутых вычислительных систем. Другим важным достоинством изучения языка ассемблера является возможность детального ознакомления с весьма слож- ной архитектурой этой вычислительной системы, предоставляю- щей пользователю разнообразный набор команд и режимов ад- ресации, что существенно упрощает программирование на языке ассемблера VAX по сравнению с использованием аналогичных средств других ЭВМ более простой архитектуры. Совершенно очевидно, что за богатство возможностей данного языка ассем- блера необходимо «расплачиваться» повышенной трудоемкостью изучения его средств программирования. Однако определенная сложность архитектуры и набора команд VAX удачно компен- сируется сравнительной простотой программирования благодаря «ортогональности» команд языка ассемблера. Так, например, освоив индексирование как один из принципов программирова- ния, можно его использовать впоследствии применительно по- чти к любому операнду любой команды. Основные положения, цель и средства Посвященную структурному программированию на языке ас- семблера системы VAX-11 эту книгу следует рассматривать пре- жде всего как учебное пособие, которое, однако, с успехом мо- жет быть использовано профессиональными программистами в качестве справочного материала.
8 Предисловие Структурное программирование Принципы структурного программирования определяют ос- нову изложения: алгоритм решения задачи сначала описывается на псевдокоде, а затем «переводится» на язык ассемблера; та- кая последовательность построения программы каждого рассма- триваемого примера в сочетании с неизменным соблюдением принципа поэтапного перехода от описания более крупных фраг- ментов к их детализации (переход от общего к частному, т. е. «сверху вниз») делает разрабатываемые программы легко чи- таемыми. Такому подходу отдается предпочтение даже несмотря на то, что это приводит иногда к снижению эффективности вы- полнения разработанных программ, впрочем, как правило, сни- жению незначительному. Завершенность примеров программ Почти все программы, приводимые в книге в качестве при- меров, являются законченными решениями задач, самостоя- тельных по своей постановке. Процедуры ввода и вывода, как правило, реализованы посредством макрокоманд, оперирующих целочисленными данными трех типов и строками символов. Со- ответствующие подпрограммы, обеспечивающие выполнение процедур ввода и вывода, приведены в приложении Г, которое содержит также процедуры выдачи дампа содержимого регист- ров и памяти. Помощь начинающему программисту В конце каждой главы приведены резюме излагаемого, пере- чень новых терминов и команд, а также сформулированы во- просы и упражнения для самопроверки, сочетающие контроль усвоения материала с выработкой практических навыков про- граммирования. Учебное программное обеспечение Программу, являющуюся эмулятором учебной машины TOYCOM, и пакет подпрограмм ввода-вывода системы VAX, записанныенамагнитной ленте, можно приобрести за небольшую плату, если обратиться непосредственно к автору книги (Инже- нерный факультет университета Колорадо, Колорадо-Спрингс, США) или представителям издательства Benjamin/Cummings, Отладчик VAX/VMS Отдельная глава книги целиком посвящена средствам от- ладки программ на языке ассемблера, именуемым отладчиком!
Предисловие 9 VAX/VMS. Описываются его основные команды, наиболее важ ные и часто используемые, приводится полный текст сеанса от- ладки. Описание полного набора команд Книга содержит описание всех доступных пользователю ко- манд системы VAX. (При использовании книги в качестве посо- бия при проведении учебных занятий по программированию на языке ассемблера выбор материала и последовательность его изложения определяются преподавателем.) Подсистема RMS Отдельная глава книги содержит детальное описание средств управления обменом данными между ЭВМ и периферийными устройствами. Эта подсистема операционной системы VAX/VMS, получившая название RMS, используется средствами автомати- зации программирования на языках высокого уровня для реа- лизации процедур ввода и вывода. Рекомендации по использованию книги в учебном процессе Содержание книги задумано автором как учебное пособие стандартного курса по программированию на языке ассемблера в соответствии с разделом CS3 «Рекомендаций АСМ 1978 по со- ставлению учебных программ» (АСМ, 1978, Curriculum Recom- mendations). Этому курсу должно предшествовать освоение хотя бы одного языка программирования высокого уровня. В гл. 1 описываются архитектура и язык ассемблера некой модели вычислительной машины, именуемой TOYCOM. Она предназначена для выполнения операций десятичной арифме- тики, располагает дюжиной команд, памятью объемом 100 слов и единственным регистром — аккумулятором. Как уже упомина- лось выше, в распоряжение обучающегося можно предоставить интерактивный эмулятор машины TOYCOM, позволяющий созда- вать и выполнять отладку программ на языке ассемблера TOY- COM. Глава 1 выполняет роль введения в организацию этой учебной машины и принципы программирования ее на языке ассемблера. Для тех, кто имеет определенные навыки и опыт программирования на ЭВМ, а также тем, кому желательно сра- зу же приступить к использованию системы VAX, можно реко- мендовать ограничиться беглым ознакомлением с содержанием гл. 1, знание которого не является обязательным для изучения основного материала книги. В гл. 2 рассматриваются двоичная и шестнадцатеричная си- стемы счисления, операции сложения и вычитания двоичных и
10 Предисловие шестнадцатеричных чисел, правила преобразования чисел из од- ной системы счисления в другую, запись двоичных чисел в до- полнительном коде. Очевидно, что материал этой главы может оказаться знакомым обучающимся и тогда его следует исклю- чить из рассмотрения. Основу книги составляют гл. 3—11, в которых анализируют- ся архитектура системы VAX, ее команды, программирование ветвящихся и циклических вычислительных процессов, отладка Программ под управлением операционной системы VMS, индек- сация, манипуляция строками символов, подпрограммы, макро- команды, т. е. все то, что в конечном счете определяет принципы и технику программирования на языке ассемблера VAX. В гл. 12—15 завершается описание набора команд системы VAX и излагаются средства подсистемы ввода-вывода RMS. Выражение благодарности Учебники и учебные пособия — результат работы большой группы людей на протяжении значительного интервала времени. Многие из тех, кто внес свой вклад в создание этой книги, за- служивают быть упомянутыми. К. Клингенстейн и штат сотрудников Вычислительного цен- тра Университета Колорадо в Колорадо-Спрингс щедро предо- ставляли память на магнитных дисках и машинное время для редактирования и форматирования текста, не жалели лент для печатающего устройства, всегда были готовы дать добрый совет. С рукописью знакомились Т. Башкоу из Колумбийского универ- ситета, М. Файман из Иллинойсского университета, Г. Райс из колледжа Де-Анза, А. Гилл из Калифорнийского университета в Беркли, Г. Лейтер из Гарвардского университета (Айкенская вычислительная лаборатория) и Р. Мюллер из Бостонского уни- верситета. Все они внесли определенный вклад в улучшение книги. Особую благодарность хочется выразить Р, Л. Лари за техническую работу над рукописью. Он был одним из разработ- чиков набора команд системы VAX и его советы существенно улучшили точность, полноту и качество изложения материала. Студенты Университета Колорадо, которым в 1982 году я преподавал язык ассемблера, заслуживают выражения особой признательности за упорство, с которым они, осваивая програм- мирование на VAX, преодолевали типографские и другие ошибки начального варианта рукописи книги. Многие (хотя и не все) из их замечаний были справедливы и носили конструктивный ха- рактер. В процессе работы над рукописью сотрудники издательства Benjamin/Cummings Дж. Нун и А. Апт постоянно оказывали мне поддержку и давали ценные советы, а их коллега С. Харрисон,
Предисловие 11 координатор работ по выпуску книги, вложила много труда в организацию подготовки рукописи к печати, особенно в налажи- вании моих контактов с художником-оформителем окончатель- ного варианта текста книги. Дж. Крошар заслуживает выраже- ния моей признательности, во-первых, за формулировку несколь- ких ключевых положений гл. 1 и, во-вторых, за инициативу по привлечению меня к написанию учебников и учебных пособий. Наконец я хочу поблагодарить мою жену Джоан за терпение, проявленное в течение бесконечных часов работы за терминалом ЭВМ по составлению и редактированию рукописи этой книги. Роберт Сибеста Колорадо-Спрингс, Колорадо
Глава 1 Вычислительные машины простой архитектуры Дель данной книги — убедить читателя, возможно хорошо вла- деющего программированием на языках высокого уровня, при- ступить к детальному изучению архитектуры ЭВМ серии VAX и языка ассемблера этих машин. И в частности, мы хотим научить студентов создавать сложные программы на языке ассемблера. Однако уместно задать вопрос: стоит ли тратить время и си- лы, чтобы научиться программированию на ассемблере, когда практически все ЭВМ продаются с весьма обширным и хорошо организованным программным обеспечением, включающим, как правило, компиляторы или интерпретаторы современных языков высокого уровня, обеспечивающих хорошее структурирование программ и реализацию модульного принципа программирова- ния? Автор видит, по крайней мере, два побудительных мотива для изучения языка ассемблера. Во-первых, несмотря на то что большая часть программных продуктов создается на языках вы- сокого уровня, для ряда приложений сохраняется практика раз- работки программ на языке ассемблера. В частности, так назы- ваемые драйверы ввода-вывода низшего уровня и некоторые другие программы часто пишутся на языке ассемблера, посколь- ку требуют прямого доступа к потенциальным возможностям машины. Подобного рода программное обеспечение часто также составляется на специализированных языках, разрабатываемых для каждой машины в отдельности. Эффективное использование этих языков возможно при наличии опыта, получаемого при изу- чении языка ассемблера соответствующей ЭВМ. В целях достижения наибольшей эффективности вычисли- тельных ресурсов при необходимости выполнения большого объ- ема арифметических операций самые внутренние циклы вычис- лений программируются на языке ассемблера. Существует также большое число задач, решаемых в мас- штабе реального времени и требующих исключительно быстрой реакции вычислительной системы на внешние воздействия и про- цессы, строго привязанные к определенным моментам времени. Программирование подобных задач эффективно только на языке ассемблера.
Вычислительные машины простой архитектуры 13 Во-вторых, изучение языка ассемблера дает понимание орга- низации вычислительных процессов в ЭВМ, которое практиче- ски невозможно получить другим способом. Глубокое понима- ние принципов работы ЭВМ позволяет конструировать лучшие программмы и на языках высокого уровня. Супермини-ЭВМ VAX-11 (сокращенно VAX) относятся к со- временным вычислительным машинам, архитектура которых основана на многих положительных конструктивных решениях ЭВМ предшествующих поколений. Как следствие, эта архитек- тура оказывается весьма сложной. Относительно сложным яв- ляется и язык ассемблера этих машин. По этой причине в дан- ной книге сначала рассматриваются основные принципы орга- низации вычислительной машины и программирования на языке ассемблера на примере очень простой модели ЭВМ. Эта упро- щенная машина под названием TOYCOM (сокращенное от toy computer — игрушечный компьютер) фактически существует только в виде имитирующей программы, написанной на языке высокого уровня. Ознакомление с TOYCOM, несмотря на его простоту, позволяет получить хорошее представление о выпол- нении вычислительных процессов в ЭВМ и о принципах про- граммирования на языке ассемблера. 1.1. Обобщенная структура TOYCOM TOYCOM разрабатывалась исключительно в педагогических це- лях. Других задач создатели этой машины перед собой не ста- вили. Перед изучением современной вычислительной системы це- лесообразно познакомиться с TOYCOM. Замена современной вы- числительной машины подобной VAX на TOYCOM позволяет не рассматривать многие сложные характеристики реальной ма- шины, часто неудобные для начального освоения. Однако TOYCOM присущи многие особенности реальной машины и в вопросах производительности, и в способности создавать весьма непростые и поучительные ситуации для пользователя. Знакомство с TOYCOM начнем с рассмотрения схемы ее об- щей структуры (рис. 1.1). TOYCOM состоит из устройства ввода, памяти, центрального процессора (ЦП) и устройства вывода. На рис. 1.1 сплошными линиями обозначена пересылка данных, а пунктирными — пересылка сигналов управления. В централь- ный процессор входят регистр команд (РК), счетчик команд (СК) и регистр, именуемый аккумулятором (АК) !). Регистры *> Наряду с русской аббревиатурой в данной книге для обозначения од- них и тех же регистров будет использоваться латинская аббревиатура. Ре- гистры РК, СК, АК соответственно имеют обозначения IR, PC, ACC. Это нужно иметь в виду особенно при чтении программ. — Прим, ред.
14 Глава 1 представляют собой специальные ячейки памяти, обмен инфор- мацией с которыми происходит с большой скоростью. Регистры имеют такой же размер, как и ячейки основной памяти, рас- сматриваемые ниже. Регистр, называемый аккумулятором, яв- ляется источником исходных данных и местом записи резуль- тата выполнения многих команд TOYСОМ. Образно говоря, аккумулятор — это то место, где происходит большинство основных событий во время вычислительного процесса. Объяс- Память Централь- ’ ный процессор (ЦП) Рис. 1.1. Общая структура TOYCOM. нить назначение регистра команд и счетчика команд несколько сложнее; эти элементы ЦП будут рассмотрены в одном из по- следующих разделов данной главы. Память TOYCOM состоит из последовательности отдельных ячеек, именуемых словами. В каждом слове памяти может хра- ниться четырехзначное десятичное число со знаком. Таким обра- зом, TOYCOM может оперировать числами в диапазоне от •—9999 до +9999. В ячейках памяти TOYCOM не предусмотрено хранение символа десятичной точки, разделяющего целую и дробную части числа. Поэтому такие числа хранить и обраба- тывать в TOYCOM нельзя. Это было бы серьезным недостатком, будь TOYCOM реальной вычислительной машиной. Однако, как упоминалось выше, TOYCOM является лишь имитацией ЭВМ и не обязана конкурировать по своим возможностям с другими
Вычислительные машины простой архитектуры 15 вычислительными машинами. Память TOYCOM состоит из 100 слов, к которым можно обращаться, используя в качестве их адресов целые числа от 0 до 99. Устройства ввода и вывода в TOYCOM объединены в единое устройство — терминал. Ввод данных осуществляется через кла- виатуру, а вывод — на дисплей или на печатающее устройство. 1.2. Машинные команды Как ни странно, но набор команд, которые может выполнять та или иная вычислительная машина, невелик и представлен от- носительно небольшой группой сравнительно простых операций. Большинство операторов языков высокого уровня слишком сложны для непосредственного выполнения на ЭВМ. Поэтому программы, написанные на таких языках, перед выполнением должны переводиться (транслироваться) на язык машинных команд. Почти всегда машинные команды состоят из двух частей: кода операции (КОП) и одного или нескольких операндов. КОП — это просто число, используемое в качестве имени, иден- тифицирующего команду. Операнд обычно является ссылкой на один или несколько адресов памяти ЭВМ. Говоря упрощенно, КОП определяет, что должно быть сделано, а операнд — над чем должна быть выполнена эта операция. Несмотря на то что TOYCOM намного проще реальных со- временных ЭВМ, ее команды имеют такую же структуру. Од- нако, поскольку TOYCOM проектировалась как прострая вычис- лительная система, набор ее команд невелик и сами команды до- статочно просты. 1.3. Выполнение программы, хранимой в памяти Перед рассмотрением набора команд системы TOYCOM целе« сообразно познакомиться с тем, как выполняются программы а ЭВМ вообще и в TOYCOM в частности. Как и большинство дру- гих ЭВМ, TOYCOM — вычислительная машина с записью про- граммы в память (с запоминаемой программой). Это значит, что машина может выполнять только те команды, которые нахо- дятся в ее оперативной памяти. Для ЭВМ с запоминаемой про- граммой типичен следующий режим работы: сначала вся про- грамма целиком считывается в оперативную память, а затем на- чинается выполнение ее отдельных команд. Альтернативным решением является считывание с входного устройства одиночной программы, ее выполнение и последующее повторение операций считывания и выполнения до тех пор, пока не встретится коман- да STOP (останов). Одна из важных побудительных причин
16 Глава 1 использования режима работы с записью программы в память заключается в том, что в таком случае машина может выпол- нять команды намного быстрее, чем они могут поставляться входными устройствами. Для извлечения слова из оперативной памяти требуется намного меньше времени, чем для его ввода с входного устройства. Поэтому хранение подлежащей выполне- нию программы в памяти машины более эффективно. Другое не- маловажное достоинство такого решения — эффективность орга- низации циклического выполнения групп команд. Необходимость в выполнении подобных циклов встречается почти во всех про- граммах. Если бы команды выполнялись одна за одной по мере их ввода в машину, для циклического выполнения группы команд пришлось бы вводить эти группы повторно при каждом очеред- ном прохождении цикла. В одной из примитивных ЭВМ начала 50-х годов, называвшейся «программируемый перфоратор», дей- ствительно использовалась такая неудобная процедура. При хранении же команд в памяти организация циклов не представ- ляет проблем. Для этого достаточно иметь возможность выпол- нения одной за другой команд, не обязательно расположенных друг за другом. Известно, что принцип выполнения хранимой в памяти про- граммы лежит в основе функционирования большинства элек- тронных цифровых вычислительных машин. В то же время ра- бота в соответствии с этим принципом порождает ряд проблем, связанных с обеспечением корректности разработки программ на некоторых языках программирования. Поскольку команды и данные хранятся в одной и той же оперативной памяти, а еди- ный принцип организации такого хранения не позволяет машине проводить различие между командами и данными, оказывается возможным выполнение одних команд программы над другими. Другими словами, поскольку машина способна выполнить ту или иную операцию, приводящую к изменению информации в обла- сти памяти, содержащей данные, она может выполнить анало- гичную операцию и над областью памяти, содержащей команду. Вообще это полезное и мощное средство ЭВМ. Однако исполь- зовать его нужно с большой осторожностью, ибо программы в принципе могут начать модифицировать себя и в тех случаях, когда их разработчик не преследовал такой цели. Сравнительно недавно подобного рода случайные модификации команд (или даже полное разрушение их структуры) были одним из наиболее распространенных типов ошибок в программах. В действитель- ности первые версии машинных языков ориентировались на раз- работку программ, способных модифицировать самих себя. По- следующие поиски путей совершенствования эффективности про- граммирования показали нежелательность наличия таких свойств у программы. Во многих современных языках програм-
Вычислительные машины простой архитектуры 17 мирования (таких, как язык Паскаль) получение программ с такими свойствами невозможно. Однако языки низкого уровня, например язык ассемблера VAX, не имеют аналогичных средств защиты. Тем не менее они сформированы так, что позволяют программисту не прибегать к модификации программой ее же собственных частей. 1.4. Набор команд TOYCOM Коды операций в командах TOYCOM являются двухразрядными десятичными числами, хранимыми в двух первых десятичных разрядах слов (ячеек) оперативной памяти. В подавляющем большинстве случаев операнды команд TOYCOM почти исклю- чительно представляют собой адреса ячеек памяти. Эти адреса выражаются также двухразрядными десятичными числами и размещаются в двух последних десятичных разрядах слов па- мяти. В общем виде команду TOYCOM можно представить сле- дующим образом: ААВВ, где АА — код операции (КОП), а ВВ — операнд, определяющий адрес ячейки памяти. В то время как программа на языках высокого уровня за- писывается в виде последовательности операторов, программа в машинных кодах TOYCOM является последовательностью четы- рехразрядных десятичных чисел. Поскольку TOYCOM — ма- шина с запоминаемой программой, в ней отсутствуют средства, определяющие, чем является то или иное слово памяти — коман- дой или данными. Любое слово памяти, выбираемое процессо- ром для выполнения, рассматривается им как команда. Какое слово памяти выполнять процессору следующим, определяется кодом предыдущей команды и реализованной в машине логикой управления последовательностью выполнения команд. В TOYCOM предусмотрены средства для ввода и вывода данных. Так, по команде IN (КОП = 07) на экран дисплея или устройство печати выводится знак вопроса, после чего система Переходит в состояние ожидания ввода пользователем некото- рого числа. После набора числа на клавиатуре и нажатия кла- виши «возврат каретки» система помещает это число в опера- тивную память по адресу, указываемому операндом команды IN. Например, команда 0742 вызовет ввод числа с клавиатуры и за- грузку его в ячейку памяти с адресом 42. Можно отметить, что Запись числа в оперативную память по заданному адресу коман- дой или каким-либо другим способом всегда приводит к уничто- жению хранившегося там старого числового значения. Команда OUT (КОП = 08) обеспечивает вывод на устрой- ство печати или экран дисплея числа из оперативной памяти в следующем виде: «OUTPUT = число». Например, если по ад- ресу 22 памяти находится число 427, то по команде 0822 будет напечатано «OUTPUT = 427».
18 Глава 1 Операции ввода и вывода не меняют содержимого аккумуля* тора. Также не изменяется и содержимое произвольной ячейки памяти после вывода его на печать. Две команды системы TOYCOM предназначены для пересыл- ки данных между аккумулятором и памятью. По команде LOAD (КОП = 01) в аккумулятор загружается копия числа, храни- мого в адресуемой ячейке памяти. Выполнение команды LOAD не изменяет содержимое этой ячейки. Команда STORE (КОП = 02) выполняет действия, противо- положные команде LOAD. Она пересылает копию содержимого аккумулятора в указываемое место оперативной памяти. Как и в предыдущей команде, хранимое и предназначенное для пере- сылки число (в данном случае содержимое аккумулятора) при выполнении команды STORE не изменяется. Примеры выполне- ния команд LOAD и STORE приведены на рис. 1.2. Команды для выполнения арифметических действий в TOYCOM просты по своей структуре и похожи одна на другую. При их выполнении предполагается, что значение первого опе- ранда находится в аккумуляторе. Вторым операндом всегда яв- ляется адресуемая в команде ячейка памяти. Результат выпол- нения операции помещается в аккумулятор, что приводит к уничтожению его предыдущего содержимого — значения первого операнда. В качестве примера рассмотрим выполнение команды сложения — команды ADD (КОП = 03). По команде, заданной четырехразрядным десятичным кодом 0327, содержимое акку- мулятора наращивается на величину, хранимую по адресу 27. На языке высокого уровня это могло бы быть записано как ACC: = АСС + С(27) Здесь и далее запись вида С (адрес) используется для обозна- чения числа, находящегося по соответствующему адресу. Другие арифметические команды выполняются аналогично. Они имеют следующие коды операций: 04 для SUBTRACT (вы- читание), 05 для MULTIPLY (умножение) и 06 для DIVIDE (деление). Команда STOP (КОП = 0) выглядит по сравнению с другими несколько необычно: она не требует задания операнда и, кроме того, может записываться как 0000, или как 0. В TOY- COM используются еще и другие команды, но они рассматри- ваются после примера простой программы, составленной из опи- санных выше команд. А Пример 1.1. Сложение двух чисел 9 Постановка задачи Исходные данные: два числа. Искомый результат: сумма исходных чисел, заданных в каче- стве входных данных.
Вычислительные машины простой архитектуры 19 АК + 0026 б АК +0423 АК -0041 Рис. 1.2. Примеры выполнения команд LOAD и STORE: а) начальное состоя- ние; б) состояние после выполнения команды 0127; в) начальное состояние; г) состояние после выполнения команды 0236.
20 Глава 1 Разработка программы состоит из двух этапов. На первом этапе должен быть создан алгоритм решения задачи. На втором этапе алгоритм должен быть преобразован в последовательность машинных команд. Несмотря на то что часто привлекательным может показаться непосредственное написание программы для ЭВМ на соответствующем языке, выполнение таких этапов имеет определенные преимущества. Алгоритм решения задачи может быть наиболее эффективно разработан и сформулирован при использовании некоторого структурного языка, называемого псевдокодом. Псевдокод со- стоит из набора операторов какого-либо развитого языка высо- кого уровня и дополнительных неформальных описаний в виде сокращенных английских фраз!). Для псевдокодов обычно не строятся трансляторы, поскольку главное назначение псевдо- кода— быть средством для упрощения записи программ. Про- грамма в примере 1.1 будет разработана без использования в псевдокоде операторов языков высокого уровня, и поэтому их бо- лее полное описание будет дано позднее. • Алгоритм, решения задачи на псевдокоде Ввести исходные данные (два числа) Вычислить SUM Вывести на печать SUM Конец программы Простой вид получившейся записи алгоритма на псевдокоде является следствием простоты решаемой задачи, но уже и этот простейший пример позволяет почувствовать удобство использо- вания неформальных элементов в псевдокоде. Легко убедиться в том, что программа из машинных команд TOYCOM, реализующая этот алгоритм, может быть построена с использованием описанных выше команд, составляющих лишь часть полного множества команд машины. Так, операциям «вве- сти исходные данные» и «вывести на печать» соответствуют команды IN и OUT. Кодирование операции «вычислить» посред- ством рассмотренного выше подмножества команд также не дол- жно вызывать затруднений. Имеется, однако, одна операция, не- явным образом присутствующая в приведенном описании на псевдокоде. Это — назначение адресов памяти используемым в программе переменным. При программировании отдельно долж- но приниматься решение о том, какие ячейки памяти будут вы- делены каждой из переменных, входящих в запись алгоритма о) Распространены псевдокоды и на других языковых основах, в част* ности на русской. Далее для элементов псевдокода, не являющихся прямыми заимствованиями из языков высокого уровня, будут использоваться русские эквиваленты. — Прим, перев,
Вычислительные машины простой архитектуры 21 на псевдокоде. В данном случае в алгоритме на псевдокоде не определены даже идентификаторы (имена) переменных, исполь- зуемых для представления входных данных. Присвоим этим пе- ременным имена FIRST и SECOND. Помимо них в программе используется еще одна переменная, предназначенная для суммы. Пусть ее имя будет SUM, как уже записано в тексте на псевдо- коде. Программы загружаются в память TOYCOM начиная с ад- реса 0, всегда являющегося адресом первой программы. Если в программе отсутствуют какие-либо команды помимо рассмотрен- ных выше, то их выполнение будет происходить последователь- но, одна за другой: после первой команды с адресом 0 будет выполнена команда по адресу 1 и т. д. до тех пор, пока не встре- тится команда STOP. Пусть переменные размещаются в верхних разделах опера- тивной памяти, т. е. в ячейках с наибольшими возможными зна- чениями адреса. При этом они окажутся максимально удален- ными от ячеек, содержащих команды. Пусть, в частности, для рассматриваемого примера значение переменной FIRST хранит- ся по адресу 99, SECOND — по адресу 98, a SUM — по адресу 97. Заметим, что машина не воспринимает имена переменных, присвоенные им на этапе создания псевдокода. Как бы такие имена ни были полезны программистам, они не используются в программах TOYCOM на машинном языке. Теперь мы готовы рассмотреть программу для примера 1.1. Первые две команды программы являются командами ввода и соответствуют первой строке записи программы на псевдо- коде: 0799 0798 По этим командам первое число загружается в ячейку памяти с адресом 99, а второе — в ячейку с адресом 98. На следующем шаге в машинные команды должна быть пре- образована очередная строка программы на псевдокоде, а имен- но «вычислить SUM». При вычислении подобных арифметиче- ских выражений обычно используются бинарные арифметические операции, т. е. имеющие два операнда, значения которых хра- нятся в памяти ЭВМ. Особенность выполнения арифметических операций в TOYCOM заключается в том, что первый операнд команды всегда находится в регистре, именуемом аккумулятором (АК). Поэтому в программе значение переменной FIRST сна- чала помещается в аккумулятор. В свою очередь, после выпол- нения команды сложения остается только перенести результат обратно в оперативную память по адресу SUM. Эта последняя
22 Глава 1 операция выполняется при работе с любой системой машинных команд. При условии соблюдения перечисленных требований по- лучаем следующую последовательность команд: 0199 0398 0297 Последовательность таких трех команд типична для всевозмож- ных присваиваний переменным значений арифметических выра- жений, требующих выполнения одной арифметической операции. Текст программы завершается командами вывода на печать ис- ходных данных ’> и результата, за которыми следует команда STOP. Полный текст программы на машинном языке TOYCOM с со- ответствующими комментариями для каждой команды имеет следующий вид: Адрес области памяти Команда Комментарий 0 0799 Ввод первого исходного числа в область памяти FIRST 1 0798 Ввод второго исходного числа в область памяти SECOND 2 0199 Загрузка содержимого области FIRST в аккумулятор 3 0398 Сложение содержимого области SECOND с содержимым аккумулятора 4 0297 Пересылка содержимого аккумулятора в область SUM 5 0899 Вывод содержимого области FIRST 6 0898 Вывод содержимого области SECOND 7 0897 Вывод содержимого области SUM 8 0000 Останов (STOP) (Последовательные номера команд в программе являются адресами областей памяти, содержащих эти команды.) *> Эта операция не предусмотрена в исходной записи данной программы на псевдокоде, — Прим, перев.
Вычислительные машины простой архитектуры 23 1.5. Функционирование машины: цикл извлечения и выполнения команды Рассмотрим более детально выполнение программ в TOYCOM и роль в этом процессе счетчика команд (СК) и регистра команд (РК). Подобно другим вычислительным машинам TOYCOM при выполнении программ работает циклически. Каждый цикл из- влечения и выполнения команды состоит из двух основных ша- гов: извлечения команды из памяти и выполнения команды. Каждый из этих шагов в свою очередь состоит из выполнения ряда определенных действий. Счетчик команд используется в качестве указателя на область памяти, из которой должна быть извлечена команда, подлежащая выполнению следующей. Во время извлечения команды — первого шага рассматривае- мого цикла работы машины — из счетчика команд извлекается адрес очередной команды. Затем расположенная по этому адресу команда пересылается из оперативной памяти в РК централь- ного процессора. Сразу после операции извлечения содержимое СК получает приращение. Во время второго шага рассматривае- мого цикла работы машины осуществляется фактическое выпол- нение команды, находящейся в этот момент в РК. Выше отмечалось, что в TOYCOM программы загружаются в оперативную память всегда, начиная с адреса 0. В соответ- ствии с этим исходное содержимое СК должно иметь значение 0. Если в программе нет циклов или ветвлений, содержимое СК по- следовательно получает единичные приращения по мере выпол- нения команд программы. Так в машине реализуется периодиче- ское повторение цикла извлечения и выполнения команды до тех пор, пока не встретится команда STOP. 1.6. Принятие решения при альтернативных возможностях выполнения программы В большинстве языков програмирования имеются операторы, позволяющие ЭВМ выбирать для последующего выполнения одну из двух возможных команд или групп команд. Такой оператор выбора включен также и в рассматриваемый нами псевдокод1*. На уровне машинных команд этому соответствует возможность изменять содержимое СК в зависимости от некоторого усло- вия. В разных ЭВМ используется разный набор условий, опре- деляющий присвоение содержимому СК того или иного очеред- ного значения. Как и можно было ожидать, в TOYCOM предусмотрена про- верка только простейших условий, а именно равенства нулю значения содержимого АК и превышения нуля этим значением. См. ниже в данном разделе, — Прим, перев.
24 Глава 1 Команды, меняющие содержимое СК, обычно называются командами перехода или передачи управления. В TOYCOM имеются команда BRANCH GREATER-THAN-ZERO (ПЕРЕХОР ЕСЛИ БОЛЬШЕ НУЛЯ), код операции которой равен 10, и команда BRANCH ZERO (ПЕРЕХОД, ЕСЛИ НУЛЬ) с кодом операции, равным 11. По команде BRANCH GREATER-THAN-ZERO процессор пе- ресылает содержимое РК в СК, если значение содержимого АК больше нуля. По команде BRANCH ZERO выполняется анало- гичная операция, если содержимое равно нулю. Если же в момент выполнения команды перехода проверка заданного условия дает отрицательный ответ, эта команда пере- дачу управления не осуществляет, и для выполнения выбирается команда, расположенная в памяти непосредственно за данной, Предположим, например, что по адресу 14 расположена коман- да 1042. При выполнении команды проверяется содержимое АК. Если оно больше нуля, процессор TOYCOM перешлет число 42 из РК и СК. В результате следующей будет выполняться коман- да, расположенная в памяти по адресу 42. Если же содержимое АК равно или меньше нуля, то по данной команде не выпол- няется никаких действий, а следующей будет выполняться команда, расположенная в памяти по адресу 15. При использовании языков высокого уровня, обеспечиваю- щих реализацию принципов модульного программирования, воз- можно создание программ без применения операторов безуслов- ного перехода. При программировании на любом машинном языке невозможно обойтись без использования команд безу- словного перехода, поскольку такие языки не содержат коман- ды, обеспечивающие сложные формы передачи управления, в которых очень часто возникает необходимость. В TOYCOM имеется команда безусловного перехода BRANCH, код операции которой 09. По этой команде содержимое РК, являющееся ее операндом, пересылается в СК независимо ни от содержимого АК, ни от содержимого какой-либо ячейки памяти. Итак, выше рассмотрены все команды TOYCOM. Они све- дены в следующую таблицу: коп Выполняемые операции 00 01 Останов Загрузка в аккумулятор (пересылка содержимого области памяти в АК) 02 Запись в память (пересылка содержимого АК в память)
Вычислительные машины простой архитектуры 25 коп Выполняемые операции 03 04 05 06 07 08 09 10 11 Сложение Вычитание Умножение Деление Ввод Вывод Переход безусловный Переход, если больше нуля Переход, если равно нулю Теперь закончим начатое выше описание псевдокода. Из- вестны три основные формы передачи управления от одного оператора (команды) программы к другому: последовательно, выбором и циклически. С их помощью можно описать любую программу. В описываемом здесь псевдокоде эти формы имеют следующий вид: Последовательная передача управления (от оператора к опе- ратору по мере их следования в программе) оператор 1 оператор 2 оператор п Передача управления выбором направления дальнейшего хода выполнения программы (посредством оператора выбора) IF условие THEN один или несколько операторов [ELSE один или несколько операторов] ENDIF Циклическая передача управления с предварительной про- веркой логического условия (посредством оператора цикла) WHILE условие DO один или несколько операторов END-DO
23 Глава 1 Эти формы передачи управления могут показаться особенно привычными для тех, кто знаком с языком Паскаль. Отличие только в ключевых словах ENDIF и END-DO, закрывающих IF- и WHILE-конструкции. Они введены для явного указания нижней границы последовательностей операторов, выполняемых согласно этим операторам псевдокода. Квадратными скобками показано, что группа ELSE в операторе IF не обязательна. Еще одно отличие введенных конструкций от аналогичных операто- ров в языке Паскаль заключается в отсутствии ключевых слов BEGINEND. С помощью псевдокода можно описать процесс выполнения команд в TOYCOM: Начальная загрузка числа 0 в СК Извлечение команды из памяти и загрузка ее в РК Приращение содержимого СК WHILE КОП команды в RK < 0 или > О DO Выполнение команды в РК Извлечение команды из памяти и загрузка ее в РК Приращение содержимого СК END-DO Конец программы Эта запись на псевдокоде показывает, как увеличивается со- держимое СК во время каждого выполнения цикла. (Заметим, что условие «<0 или >0» означает «не равно 0».) Теперь имеется все необходимое для записи программ, в ко- торых выполняется передача управления в результате принятия решения при альтернативных возможностях выполнения про- граммы. Рассмотрим пример одной такой относительно не слож- ной программы. А Пример 1.2 • Постановка задачи Исходные данные: два числа. Искомый результат: наибольшее из двух заданных чисел. • Алгоритм, решения задачи на псевдокоде Ввести исходные данные (два целых числа FIRST и SECOND) IF FIRST > SECOND THEN вывести на печать значение FIRST ELSE вывести на печать значение SECOND ENDIF Конец программы
Вычислительные машины простой архитектуры 27 При формировании программы в машинных кодах прежде всего должно быть выполнено назначение адресов областей памяти всем переменным, встречающимся в записи программы на псевдокоде. В соответствии с этим, как и в предыдущем при- мере, пусть переменная FIRST размещается по адресу 99, а SECOND — по адресу 98. Первая часть программы может быть записана сразу же н виде последовательности кодов 0799, 0798 (как в примере 1.1). Несколько больших усилий требует программирование опера- тора IF. Требуется, в частности, решить, с помощью какой ма- шинной команды будет выполнена соответствующая операция. Заметим, что если операторы группы THEN будут предшест- вовать операторам группы ELSE (что можно считать наиболее естественным *> порядком), то необходимо воспользоваться опе- рацией условного перехода для обхода операторов группы THEN. Для этого логическое условие оператора IF должно быть изменено на противоположное. В рассматриваемом примере сна- чала должен выполняться оператор IF FIRST<=SECOND для условного перехода к операторам группы ELSE, а непосред- ственно за этим оператором условного перехода должны разме- щаться операторы группы THEN. Как же закодировать передачу управления при выполнении условия FIRST<=SECOND? Проблема состоит в том, что в псевдокоде оператор IF допускает любые условия сравнения двух произвольных величин, а в машинных командах условного перехода TOYCOM предусмотрено только две разновидности проверяемых условий, причем, в качестве одного из сравнивае- мых значений используется нуль. Ничего не остается делать, кроме как выполнять сравнение некоторой величины с нулем. В рассматриваемом примере значения переменных FIRST и SECOND должны сравниваться между собой посредством опе- рации «меньше или равно» (<=). Неравенство, являющееся условием проверки в операторе IF * 2) необходимо алгебраически преобразовать в эквивалентное, содержащее 0 в левой части. После этого отдельными машинными командами следует пред- варительно вычислить и загрузить в АК значение правой части преобразованного неравенства, а затем уже воспользоваться командами BRANCH GREATER-THAN-ZERO и BRANCH ZE- RO. Итак, требуется закодировать передачу управления при вы- полнении условия FIRST<=SECOND, которое является логи- чески обратным исходному условию в операторе IF псевдокода. При вычитании FIRST из обеих частей этого неравенства '> Но не обязательным. — Прим, перев. 2) Точнее, логически обратное ему (см. ниже) FIRST< = SECOND, ис- пользуемое в машинных командах условного перехода. — Прим, перев.
28 Глава 1 получаем: 0 < = SECOND — FIRST. Таким образом, для вы- полнения требуемой передачи управления прежде всего необхо- димо предварительно вычислить и загрузить в аккумулятор значение выражения SECOND — FIRST. Машинные команды, соответствующие группе THEN и сле- дующие за командой1) условного перехода, связанной с обработ- кой условия, соответствующего в программе на псевдокоде ус- ловного оператора IF, должны завершаться командой безуслов- ного перехода для обхода выполнения команд группы ELSE. • Программа в машинных командах TOYCOM Адрес Команда Комментарий 0 0799 Ввод значения переменной FIRST 1 0798 Ввод значения переменной SECOND 2 0198 Загрузка копии содержимого SECOND в АК 3 0499 Вычитание значения FIRST из содержимо- го АК 4 1008 Переход к выводу на печать значения SECOND, если содержимое АК>0; 5 1108 Переход к выводу на печать значения SECOND, если содержимое АК = 0 6 0899 Вывод на печать значения FIRST (по THEN) 7 0909 Переход на STOP 8 0898 Вывод на печать значения SECOND (по ELSE) 9 0000 STOP Посредством команд, расположенных в области памяти с ад- ресами 2 и 3, вычисляется, а затем загружается в АК значение выражения SECOND—FIRST. После этого по команде BRANCH GREATER-THAN-ZERO, хранимой в области памяти с адре- сом 4, в СК загружается адрес 08, если содержимое АК больше нуля (т. е. значение переменной SECOND больше значения пере- менной FIRST). Если содержимое АК больше нуля, то следую- щей выполняется команда, находящаяся в области памяти с ад- ресом 8. По этой команде выводится на печать значение пере- менной SECOND. Если же во время выполнения команды BRANCH GREATER-THAN-ZERO содержимое в АК не больше о В данном случае за двумя командами. Прим, перев<
Вычислительные машины простой архитектуры 29 нуля, то содержимое СК увеличивается на 1, и следующей вы- полняется команда, хранимая в области памяти с адресом 5. Эта команда проверяет, не равно ли нулю содержимое АК. Если оно равно нулю, то в СК помещается число 08. Следствием этого является вывод на печать значения той же переменной SECOND. В противном случае после выполнения команды BRANCH ZERO содержимое СК увеличивается на 1, в результате чего на печать выводится значение переменной FIRST. Итак, в любом случае на печать выводится большее из двух чисел, что соответствует требованиям решаемой задачи. Заметим, что в данной программе использованы две команды условного перехода. Во многих же других системах машинных команд условный переход по «больше или равно» выполняется отдельной командой. Более того, в тех случаях, когда исходные числа равны между собой, на печать может выводиться значение любого из них. Следовательно вторая команда условного пере- хода не является обязательной. Однако, такую ситуацию следо- вало бы учесть при описании алгоритма решения задачи на псевдокоде, а не требовать вывода на печать значения перемен- ной FIRST в случае FIRST > SECOND. Некоторые особенности программирования передачи управ- ления по условию рассматриваются в разд. 1.9. 1.7. Недостатки программирования в машинных кодах Некоторое знание структуры машинных команд, конечно, полез- но для понимания особенностей соответствующего языка ассем- блера. Однако (если исключить первые годы развития вычисли- тельной техники) разработку программ практически никогда не выполняют в машинных кодах. Во-первых, программистам трудно оперировать с множеством чисел и все время помнить, что они обозначают. В программиро- вании достаточно других сложных проблем, чтобы пользоваться очень неудобной числовой системой обозначений. К тому же на- глядность представления программы в машинных кодах намного снижается при переходе от TOYCOM к наборам машинных ко- манд реальных ЭВМ. В TOYCOM для обозначения кодов опера- ции используется сравнительно небольшое число десятичных раз- рядов; команды же в реальных ЭВМ более сложны по структу- ре. Хранятся эти команды в ячейках памяти, число элементар- ных состояний в которых также, как правило, не равно 10. В большинстве используемых на практике ЭВМ команды хра- нятся в памяти машины в двоичной форме (в позиционной си- стеме счисления с основанием 2), а при выводе представляются в восьмеричной или шестнадцатеричной системах счисления (с основанием 8 или 16 соответственно). В любом случае програм-
30 Глава 1 мы в машинных кодах для реальных ЭВМ крайне неудобны для чтения по сравнению с программами для TOYCOM, хотя по- следние тоже не отличаются большой наглядностью. Во-вторых, в машинных командах перехода в качестве опе- рандов должны использоваться действительные адреса других команд. Так, в примере 1.2 имеется команда передачи управле- ния по условию команде вывода, расположенной в ячейке памя- ти с адресом 7. Легко можно себе представить программу на пяти листах и более, содержащую десять или более команд пе- рехода. Пусть теперь требуется добавить еще одну команду в начальную часть программы. После добавления все прежние ад- ресные ссылки в командах переходов оказываются неверными, поскольку адреса всех команд увеличились на 1. Аналогично, удаление одной или нескольких команд из программы в машин- ных кодах требует изменения всех адресов в командах перехода, которые относятся к части программы, следующей за первым из введенных изменений. Читатель, имеющий опыт программирова- ния на языках высокого уровня, знает, как часто во время от- ладки программ приходится вносить в них изменения. Неизбеж- ность подобных изменений делает разработку программ в ма- шинных кодах непрактичной и мало эффективной. 1.8. Язык ассемблера TOYCOM Отмеченные в предыдущем разделе два недостатка программи- рования в машинных кодах явились побудительными мотивами разработки в начале 50-х годов целого класса языков програм- мирования несколько более высокого уровня, чем язык машин- ных команд. Они получили название языков ассемблера. В этих языках коды операции задаются не числами, а мнемо- ническими обозначениями — сокращениями от названий выпол- няемых операций. В них символические обозначения используют- ся также и для адресов. Более того, команды могут снабжаться метками, записываемыми в виде последовательности символов, и эти метки можно использовать в качестве операндов команд перехода. Таким образом, удобные, имеющие определенное смыс- ловое значение символические имена присваиваются кодам опе- раций, адресам команд и операндам, являющимся ссылками на 'данные. Кроме этого, языки ассемблера отличаются некоторыми дополнительными свойствами, облегчающими процесс програм- мирования. 4,8.1, Трансляторы ®ыше отмечалось, что ЭВМ. «понимает» только свой собственный Язык машинных кодов. Поэтому для любого языка, на котором разрабатывается программа, должна существовать или трансли-
Вычислительные машины простой архитектуры 31 рующая программа (для перевода операторов исходного языка в машинные команды), или интерпретирующая. Программы, составленные на языках высокого уровня, не все” гда транслируются в программы в машинных кодах. В случаях, когда такое преобразование выполняется, транслирующую про- грамму называют компилятором. Иногда же программы, напи- санные на языках высокого уровня, либо транслируются на не- который дополнительный язык промежуточного уровня, либо во- обще не транслируются. Программные системы, обеспечивающие работу по таким принципам, называются соответственно интер- претаторами и чистыми интерпретаторами. В обоих случаях про- граммы интерпретируются. Это означает, что машина выполняет трансляцию не всего текста программы целиком, а отдельно каждое предложение и сразу же после этого выполняет требуе- мые операции. Техника интерпретации может быть применена как к исходной программе, так и к результату ее трансляции на язык промежуточного уровня. В обоих случаях создаваемый ин- терпретатором машинный эквивалент операторов исходного тек- ста после выполнения не сохраняется. Вот почему любой опера- тор, являющийся составной частью тела цикла, переводится в машинный код каждый раз, когда он должен выполняться. Ин- терпретируемые программы выполняются медленнее, чем компи- лируемые, поскольку интерпретация может потребовать повтор- ной трансляции отдельных операторов исходной программы. Не- смотря на это, в ряде случаев применяют именно интерпретаторы, а не компиляторы, генерирующие полную машинную программу, поскольку они имеют более простую структуру и занимают мень- ше места в оперативной памяти. При работе в режиме интерпре- тации также относительно прост сбор и вывод информации, не< обходимой для отладки программы, в процессе выполнения ко- торой обнаружена ошибка. Транслятор с языка ассемблера обычно называют ассемблер ром. Каждая вычислительная машина имеет свой набор ма- шинных команд и почти для каждой разработан ассемблер — программа, позволяющая ЭВМ работать с программами, напи- санными на языке ассемблера данной машины. Программа, именуемая ассемблером, обрабатывает программу пользователя, написанную на языке ассемблера, в результате чего создается программа в машинных кодах. После этого может быть иниции- ровано выполнение полученной программы. Язык ассемблера является по существу символической формой записи машинного языка, поэтому каждая вычислительная машина со своим спе- цифическим машинным языком располагает своим языком ас- семблера. Последний дает возможность программисту пред- ставлять коды операций и адреса в форме символических имен. Поэтому программирование на языке ассемблера иногда
32 Глава 1 Программа на" языке высокого уровня Рис. 1.3. Преобразования, выполняемые компиляторами, интерпретаторами, чистыми интерпретаторами и ассемблерами: а) компилятор; б) интерпретатор; в) чистый интерпретатор; г) ассемблер. называют символическим кодированием. Описание языка ас- семблера вычислительной системы VAX приведено в гл. 3. Преобразования, выполняемые компиляторами, интерпрета- торами, чистыми интерпретаторами и ассемблерами, схематиче- ски изображены на рис. 1.3,
Вычислительные машины простой архитектуры 33 1.8.2. Выполняемые команды Перейдем к рассмотрению конкретного языка ассемблера, ис- пользуемого вычислительной машиной TOYCOM. Ниже в форме таблицы приведены символические имена кодов операций языка ассемблера TOYCOM. Как правило, эти имена являются сокра- щенной формой записи наименовайий машинных команд. коп в числовой форме коп в форме символи- ческого имени Название 00 STOP 1 4Л - ** Останов 01 LD Загрузка 02 STO Запись 03 ADD Сложение 04 SUB Вычитание 05 MPY Умножение 06 DIV Деление 07 IN Ввод 08 OUT Вывод 09 В Переход безусловный 10 BGTR Переход, если больше нуля 11 BZ Переход, если равно нулю В целях удобства язык ассемблера TOYCOM будет дальше называться TOYCODE. Все приведенные выше команды явля- ются действительными (выполняемыми) командами языка ас- семблера, т. е. такими, которые при трансляции превращаются непосредственно в машинные команды. 1.8.3. Директивы транслятора В дополнение к перечисленным выше командам TOYCODE, пре- образуемым в результате трансляции в машинные команды TOYCOM, в TOYCODE входят еще две команды, называемые директивами. Основное назначение директив языков ассембле- ра — передача определенной информации транслирующей про- грамме (ассемблеру). Директивы не переводятся в машинные команды. Они не находят прямого отражения в формируемой транслятором программе в машинных кодах, В большинстве 2 Зак, 483
84 Глава 1 ' -............ ------------- I ......... — языков ассемблера имеется значительное число директив. Мно- гие из них используются для выделения областей памяти подле- жащим выполнению программам. Таково, в частности, назначе- ние одной из директив TOYCODE, символическое имя которой DC является сокращением от полного наименования Define Con- stant (определить константу). Ранее было отмечено, что при построении машинных про- грамм необходимо назначать определенные адреса всем пере- менным, имена которых введены в псевдокоде. TOYCODE позво- ляет применять символические имена (в том числе и используе- мые в программах на псевдокоде) для адресации к областям памяти в программе. Необходимо только должным образом со- общить ассемблеру, обрабатывающему программу на языке TOYCODE, имена переменных этой программы. Такая связь имен и адресов устанавливается при использовании имени пере- менной в качестве метки директивы DC, обеспечивающей выде- ление (резервирование) соответствующей области памяти. Все функции по запоминанию таких связей берет на себя трансли- рующая программа (ассемблер). Согласно правилам TOYCODE, метка записывается перед командой и отделяется от КОП двое- точием. Директива DC также позволяет программисту (в дей- ствительности обязывает его) для каждой резервируемой обла- сти памяти определить начальное значение, которое получает соответствующая переменная во время ассемблирования. Если для некоторой переменной исходное значение не определено, оно может быть просто задано нулевым значением операнда. Директива DC имеет следующий формат! Метка: DC константа Например: SUM: DC О TIME: DC 100 Согласно этим двум директивам, выделяется две области памяти каждая размером в слово. Этим областям присваиваются имена (адреса) SUM и TIME и задаются начальные значения 0 для 8UM и 100 для TIME. Вторая директива TOYCODE — директива REM, выполняет простую функцию. Она позволяет программисту включать в текст программы на TOYCOM комментарии. Имя этой директи- вы (REM) является сокращением слова remark, означающего «примечание». Директива REM имеет следующий формат: REM произвольный-текст Здесь в качестве «произвольного текста» может выступать лю- бая последовательность символов. При формировании програм- мы в машинных кодах эта директива транслятором полностью
Вычислительные машины простой архитектуры 35 игнорируется и учитывается только при выводе текста програм- мы на печать. Программистам рекомендуется пользоваться этой директивой для подробного объяснения операций, выполняемых в программах. Пример использования описанных команд и ди- ректив рассматривается в следующем разделе. L8.4. Программа на языке TOYCODE Теперь имеется все необходимое для записи программы на языке TOYCODE. Рассмотрим снова пример 1.2. Текст программы на языке TOYCODE для этого примера дается ниже и параллельно приводится текст в машинных кодах: Машинные команды Команды и директивы REM ПРОГРАММА ВЫЧИСЛЕНИЯ REM НАИБОЛЬШЕГО REM ИЗ ДВУХ ВВОДИМЫХ ЧИСЕЛ REM ВВОД ДВУХ ЧИСЕЛ 0799 IN FIRST 0798 IN SECOND REM ОПРЕДЕЛЕНИЕ НАИБОЛЬШЕГО REM ЧИСЛА ПУТЕМ REM ВЫЧИСЛЕНИЯ ИХ РАЗНОСТИ 0198 LD SECOND 0499 SUB FIRST REM ЕСЛИ РАЗНОСТЬ >=0 ПЕРЕЙТИ REM К ВЫВОДУ НА REM ПЕЧАТЬ ЗНАЧЕНИЯ SECOND REM (ОНО БОЛЬШЕ) 1008 BGTR ELSE 1108 BZ ELSE REM БОЛЬШЕЕ ИЗ ДВУХ ЧИСЕЛ-FIRST 0899 OUT FIRST 0909 В FINISH REM ЕСЛИ БОЛЬШЕЕ ИЗ ЧИСЕЛ - SECOND 0898 ELSE: OUT SECOND 0000 FINISH: STOP FIRST: DC 0 SECOND: DC 0 2*
36 Глава 1 Отличительная черта программ на языке TOYCODE заклю- чается в том, что их легко читать. Текст такой программы удоб- но анализировать даже при отсутствии комментариев. И хотя тексты программ на языке TOYCODE менее наглядны, чем тек- сты программ на языках высокого уровня, приведенная выше программа (как и любая другая программа на языке ассембле- ра) намного понятнее и удобнее своего эквивалента в машинных кодах. Это становится особенно очевидным при сравнении про- граммы на языке TOYCODE с эквивалентной программой в ма- шинных кодах. 1.9. Перевод программы с псевдокода на язык TOYCODE Точность и наглядность записи программ на языке TOYCODE могут быть повышены при непосредственном переводе программ, написанных на псевдокоде, в программы на языке TOYCODE. Если при написании программы на языке ассемблера в каче- стве исходного материала использовать текст программы на псевдокоде и при этом строго соблюдать соответствующие пра- вила перевода с одного языка на другой, то получается хорошо структурированная программа. Более того, сам псевдокод мож- но использовать в качестве комментариев к программе на языке ассемблера. Это обеспечивает большую понятность результи- дующей программы на языке ассемблера. 1.9.1. Преобразование оператора цикла WHILE Обобщенное правило преобразования оператора WHILE псевдо- кода в эквивалентный текст на языке TOYCODE можно предста- вить следующим образом: Псевдокод TOYCODE WHILE условие DO тело цикла END-DO Метка начала цикла Проверка условия, инверсного ис- ходному Переход на метку выхода из цикла, если результат операции «истинно» Команды TOYCODE, реализующие операции тела цикла Метка выхода из цикла
Вычислительные машины простой архитектуры 37 Можно заметить, что при преобразовании оператора WHILE в текст на языке TOYCODE проверяется истинность инверсии исходного условия. Это во многом подобно программному реше- нию на языке TOYCODE в примере 1.2, с той лишь разницей, что в примере 1.2 условие является частью оператора выбора. Опе- ратор цикла WHILE предусматривает выполнение операторов, составляющих его тело, в случае истинности проверяемого усло- вия. Следовательно, обход этих операторов должен выполнять- ся в случае ложности условия. Однако в TOYCOM нет опера- тора условного перехода по «ложно». Поэтому исходное условие должно быть инвертировано перед выполнением команды услов- ного перехода. Особенности преобразования оператора WHILE в соответ- ствующие команды TOYCODE помогает понять приводимый ниже пример фрагмента программы, в котором осуществляется последовательный ввод чисел, подсчет в счетчике COUNTER ко- личества и вычисление суммы SUM до тех пор, пока значение содержимого COUNTER остается меньше некоторого предела — значения переменной HEADER. (При этом предполагается, что переменной SUM первоначально присвоено значение 0.) А Пример 1.3. Преобразование программы на псевдокоде с оператором WHILE в программу на языке TOYCODE • Программа. Алгоритм решения задачи на псевдокоде WHILE содержимое счетчика < предела DO Ввести число Добавить число к сумме Увеличить на 1 содержимое счетчика END-DO • Программа на языке TOYCODE REM REM REM LOOP: ДО ТЕХ ПОР ПОКА COUNTER < HEADER DO ВЫПОЛНИТЬ В ЦИКЛЕ LD COUNTER SUB HEADER BZ LOOPEND BGTR LOOPEND
38 Глава 1 REM ВВОД ОЧЕРЕДНОГО ЧИСЛА IN NUMBER REM ДОБАВЛЕНИЕ ЧИСЛА К СУММЕ LD SUM ADD NUMBER STO SUM REM УВЕЛИЧЕНИЕ СОДЕРЖИМОГО REM СЧЕТЧИКА LD COUNTER ADD ONE STO COUNTER В LOOP REM КОНЕЦ ЦИКЛА СУММИРОВАНИЯ LOOPEND: . . . ONE: DC 1 Первые две команды программы на языке TOYCODE, рас- положенные после первой директивы REM, выполняют операции проверки условия, обратного (инверсного) исходному. Команды BGTR и BZ обеспечивают выход из цикла WHILE при истинно- сти этого условия. Следующие 7 команд составляют тело цикла WHILE. За ними следует оператор безусловного перехода на начало цикла. Метка LOOPEND является меткой первой коман- ды языка TOYCODE, следующего за циклом WHILE фрагмента программы независимо от назначения этой команды. В тексте программы положение указанной команды обозначено меткой LOOPEND, за которой следует многоточие. Константа, равная 1 и необходимая для увеличения на 1 содержимого счетчика COUNTER, формируется директивой DT с меткой ONE. Ниже слева приведены знаки операций отношения, а справа знаки соответствующих операций обратных (инверсных) отно- шений.
Вычислительные машины простой архитектуры 39 '1.9.2. Преобразование оператора выбора IF В программах на псевдокоде оператор IF может встретиться в одной из двух форм: с группой ELSE или без нее. Ниже рассма- тривается пример, в котором оператор IF содержит группу ELSE. Такая форма оператора IF используется, если требуется сделать выбор между альтернативными группами операторов. Без группы ELSE оператор IF обеспечивает выбор выполнения или обхода группы операторов. Ниже приведено обобщенное описание алгоритма преобразо- вания оператора IF в эквивалентные команды языка TOYCODE. Обобщенное правило преобразования оператора IF псевдо- кода в эквивалентный текст на языке TOYCODE можно предста- вить следующим образом: Псевдокод TOYCODE IF условие Проверка условия, инверсного ис- ходному THEN операторы Переход на метку ELSE, если ре- группы THEN зультат операции «истинно» Команды TOYCODE, реализующие операторы группы THEN Переход на метку конца опера- тора IF ELSE операторы Метка ELSE группы ELSE Команды TOYCODE, реализую- щие операторы группы ELSE ENDIF Метка конца оператора IF Если в команды TOYCODE преобразуется оператор IF, не содержащий группы ELSE, условный переход должен выпол- няться не на метку ELSE (которая в таком случае отсутствует), а на метку конца оператора IF. Заметим также, что и в этом случае (как и в случае оператора WHILE) проверяться должно условие, инверсное исходному. Ниже рассматривается пример с полным оператором IF, т. е. содержащим группы THEN и ELSE. Программа выполняет уве- личение значения переменной TOTAL на 2, если SCORE > BREAK, и на 3 в противоположном случае.
40 Глава 1 Л Пример 1.4. Преобразование программы на псевдокоде с оператором IF в программу на языке TOYCODE Псевдокод TOYCODE IF SCORE > BREAK REM ЕСЛИ SCORE>BREAK LD BREAK SUB SCORE BGTR ELSE BZ ELSE THEN добавить 2 REM TO добавить 2 к TOTAL к TOTAL LD TOTAL ADD TWO STO TOTAL В ENDIF ELSE добавить 3 REM ИНАЧЕ добавить 3 к к TOTAL REM TOTAL ELSE: LD TOTAL ADD THREE STO TOTAL REM КОНЕЦ ОПЕРАТОРА IF ENDIF ENDIF: • . • Приведенный пример также иллюстрирует различие в на- глядности и длине программ на псевдокоде и языке TOYCODE. Это различие становится очевидным при сравнении любых язы- ков ассемблера с языками высокого уровня. 1.10. Примеры программ на языке TOYCODE В примере 1.5 программа должна вводить данные с признаком конца и подсчитывать процент положительных чисел из общего числа введенных. «Ввод данных с признаком конца» означает, что вслед за множеством чисел вводится особое число, не рас- сматриваемое как очередное в множестве вводимых данных. Это особое число воспринимается программой как признак того, что дальнейший ввод данных должен быть прекращен. А Пример 1.5 • Постановка задачи Исходные данные', список неравных нулю чисел, за которыми следует число 0; общее количество чисел в списке больше 1. .
Вычислительные машины простой архитектуры 41 Исходный результат: выраженное в процентах отношение количества положительных чисел к общему количеству всех вве- денных чисел. • Алгоритм решения задачи на псевдокоде (Составление программы на псевдокоде не должно представлять для читателя особых трудностей.) , Присвоение нулевого значения переменным TOTAL-DATA и POSITIVE-DATA Ввод числа в ячейку памяти NUMBER WHILE NUMBER < ) О DO увеличение TOTAL-DATA на 1 IF NUMBER положительно THEN увеличение POSITIVE-DATA на I ENDIF Ввод следующего числа в ячейку памяти NUMBER END-DO Вычисление процента положительных чисел Вывод на печать значения процента Конец программы • Программа на языке TOYCODE 10 REM ВЫЧИСЛЕНИЕ В ПРОЦЕНТАХ 12 REM ОТНОШЕНИЯ КОЛИЧЕСТВА 14 REM ПОЛОЖИТЕЛЬНЫХ ЧИСЕЛ К ОБЩЕМУ 16 REM КОЛИЧЕСТВУ ВВОДИМЫХ ЧИСЕЛ 20 REM ИСХОДНЫЕ ДАННЫЕ: СПИСОК ' REM НЕРАВНЫХ НУЛЮ ЧИСЕЛ 25' REM ЗАВЕРШАЕМЫЙ НУЛЕМ 30 REM РЕЗУЛЬТАТ: % ПОЛОЖИТЕЛЬНЫХ 40 REM ЧИСЕЛ ИЗ ОБЩЕГО КОЛИЧЕСТВА , REM ВВОДИМЫХ 50 REM ВВОД ЧИСЛА В ЯЧЕЙКУ ПАМЯТИ 60 IN NUMBER 70 REM ДО ТЕХ ПОР ПОКА NUMBER < > 75 REM 0 выполнять В ЦИКЛЕ 80 LOOP: LD NUMBER 90 BZ LOOPEND 100 REM УВЕЛИЧЕНИЕ ЗНАЧЕНИЯ TOTAL-DATA 105 REM НА 1
42 Глава 1 по LD TOTAL 120 ADD ONE 130 STO TOTAL 140 REM ЕСЛИ NUMBER ПОЛОЖИТЕЛЬНО 150 LD ZERO 160 SUB NUMBER 170 BGTR ENDIF 180 BZ ENDIF 190 REM TO УВЕЛИЧИТЬ POSITIVE- 195 REM DATA HA 1 200 LD POSITIVES 210 ADD ONE 220 STO POSITIVES 230 REM КОНЕЦ ОПЕРАТОРА IF 240 REM ВВОД СЛЕДУЮЩЕГО ЧИСЛА В ЯЧЕЙКУ 245 REM NUMBER 250 ENDIF: IN NUMBER 260 REM КОНЕЦ ЦИКЛА 270 В LOOP 280 REM ВЫЧИСЛЕНИЕ % ПОЛОЖИТЕЛЬНЫХ 285 REM ЧИСЕЛ 290 LOOPEND: LD POSITIVES 300 MPY HUNDRED 310 DIV TOTAL 320 STO PERCENT 330 REM ВЫВОД НА ПЕЧАТЬ ЗНАЧЕНИЯ 335 REM ПРОЦЕНТА 340 OUT PERCENT 350 STOP 360 REM КОНЕЦ ПРОГРАММЫ 870 REM РАСПРЕДЕЛЕНИЕ ПАМЯТИ 880 NUMBER: DC 0 390 TOTAL: DC 0 400 ONE: DC 1 410 POSITIVES: DC 0 420 HUNDRED: DC 100 430 PERCENT: DC 0 440 ZERO: DC 0
Вычислительные машины простой архитектуры 43 Целесообразно дополнительно прокомментировать некоторые особенности данной программы. Прежде всего отметим, что в качестве комментариев используется почти исключительно текст программы на псевдокоде *>. В этом одно из важных преиму- ществ описания алгоритма решения задачи на псевдокоде, а не в виде блок-схемы, поскольку описание программы, выполняемое на предварительном уровне, может стать составной частью ее окончательного полного текста. Такое использование псевдокода возможно и при разработке программ на других языках, но осо- бое значение оно имеет при работе с языками низкого уровня, к которым явно относится язык ассемблера. Таким образом, как отмечено выше, псевдокод представляет собой мощное средство и для разработки легко читаемых и структурированных про- грамм и для документирования готовой программы. Рассматри- ваемая и следующая программы снабжены нумерацией строк, необходимой при работе программного имитатора TOYCOM, (Имитатор позволяет проводить ассемблирование программ, на- писанных на языке TOYCODE, и их выполнение. Правила рабо- ты с имитатором описаны в приложении 1.) Следует также обратить внимание на то, что проверяется условие, обратное (инверсное) заданному в операторе IF. Ис- ходное условие предполагает проверку, положительно ли число NUMBER; обратное — отрицательно ли оно или равно нулю, В языке TOYCODE отсутствует команда перехода по условию «ЕСЛИ МЕНЬШЕ НУЛЯ», поэтому необходимо менять знак числа NUMBER на обратный. Это достигается вычитанием числа из нуля. После чего можно осуществлять передачу управления с помощью команд BGTR и BZ. Условие в операторе WHILE обрабатывается проще, поскольку отношением, логически обрат- ным < >, является отношение равенства (=). Передача управления реализуется одной командой BZ. В общем случае проверка условий, обратных исходным, не так уж сложна, хотя и требует некоторого навыка. И еще одно заключительное замечание. В рассмотренном примере вычисление количества положительных чисел (выра- жаемого в процентах) должно выполняться той последователь- ностью команд, которая приведена. В частности, недопустима последовательность: LD POSITIVES DIV TOTAL MPY HUNDRED *> Сказанное справедливо для текста комментариев в оригинале на анг- лийском языке. При переводе комментариев здесь и в дальнейшем использо- ваны эквивалентные термины русского языка. — Прим, ред.
44 Глава 1 Хотя с математической точки зрения данная последователь- ность и кажется верной, результат будет ошибочным. Эта после- довательность верна, только если указанные операции выполня- ются по правилам арифметики вещественных чисел, а не ариф- метики целых чисел. В так называемой арифметике целых чисел результат деления, будучи, как правило, меньше 1, округлится до 0 (до ближайшего целого, меньшего по значению). Един- ственный ненулевой результат получится при POSITIVES = TO- TAL, т. е. когда все вводимые числа положительные (искомый результат равен 100%). TOYCOM построена на базе арифме- тики целых чисел, поэтому, чтобы получить правильный резуль- тат, следует пользоваться последовательностью команд, приве- денной в программе. Это важное обстоятельство имеет отноше- ние не только к TOYCOM, но и к любой вычислительной системе, которая либо подобно TOYCOM располагает лишь арифметикой целых чисел, либо пользуется этой арифметикой по специаль- ному выбору, предусмотренному в трансляторах большинства языков программирования. Д Пример 1.6 • Постановка задачи Исходные данные: число LENGTH, определяющее длину числовой последовательности, вводимой непосредственно за LENGTH; числовая последовательность, подлежащая обработке. Искомый результат: порядковый номер наименьшего числа вводимой последовательности чисел. Задача сводится к поиску наименьшего из вводимых чисел. Программа должна выводить на печать не значение наимень- шего числа, а указатель его местоположения (порядковый но- мер) в ряду чисел. Поэтому во время выполнения программы необходима информация не только о значении текущего наимень- шего числа, но и о его порядковом номере. Заметим также, что ввод чисел осуществляется с помощью указателя количества введенных чисел, что является альтернативным способом орга- низации ввода последовательности чисел согласно принципу: ввод заканчивается при обнаружении специального признака конца последовательности вводимых чисел. • Алгоритм решения задачи на псевдокоде Ввод длины числовой последовательности (LIST-LENGTH) Присвоение переменной SMALLEST (текущему наименьшему) значения первого вводимого числа в качестве начального зна- чения Присвоение переменной DATA-COUNTER значения, равного еди- нице, в качестве начального значения
Вычислительные машины простой архитектуры 45 Присвоение переменной SMALLEST-POSITION значения, рав- ного единице, в качестве начального значения WHILE DATA-COUNTER < LIST-LENGTH DO Ввод очередного числа в ячейку памяти VALUE Увеличение на единицу содержимого счетчика DATA-COUNTER IF VALUE < SMALLEST THEN Замена содержимого SMALLEST копией содержимого VALUE Замена содержимого SMALLEST-POSITION копией содержимого DATA-COUNTER ENDIF END-DO Вывод на печать SMALLEST-POSITION Конец программы Приведенное описание алгоритма решения задачи на псевдо- коде в полной мере поясняет существо выполняемых операций. В данном случае предполагалось, что значение переменной LIST-LENGTH больше нуля. В общем случае это может ока- заться не так, но при вводе данных с терминала вероятность такого события мала и ее можно не учитывать. • Программа на языке TOYCODE 10 REM ОПРЕДЕЛЕНИЕ ПОРЯДКОВОГО 14 REM НОМЕРА 16 REM НАИМЕНЬШЕГО ЧИСЛА 20 REM ИСХОДНЫЕ ДАННЫЕ: ДЛИНА 21 REM ЧИСЛОВОЙ ПОСЛЕДОВАТЕЛЬНОСТИ 23 REM И ПОСЛЕДОВАТЕЛЬНОСТЬ 25 REM ЧИСЕЛ 30 REM РЕЗУЛЬТАТ: ПОРЯДКОВЫЙ НОМЕР 35 REM НАИМЕНЬШЕГО ИЗ ВВЕДЕННЫХ 37 REM К ЧИСЕЛ 40 50 REM REM ВВОД ДЛИНЫ ПОСЛЕДОВАТЕЛЬНОСТИ 60 JN LENGTH
46 Глава 1 70 REM ПРИСВОЕНИЕ SMALLEST 73 REM НАЧАЛЬНОГО ЗНАЧЕНИЯ 75 REM ВВОДОМ ПЕРВОГО ЧИСЛА 80 IN SMALLEST 90 REM ПРИСВОЕНИЕ DATA-COUNTER И 95 REM POSITION НАЧАЛЬНЫХ ЗНАЧЕНИИ 100 LD ONE ПО STO COUNTER 120 STO POSITION 130 REM ДО ТЕХ ПОР ПОКА DATA-COUNTER 131 REM < LIST-LENGTH ВЫПОЛНЯТЬ 133 REM В ЦИКЛЕ 135 REM 140 LOOP: LD COUNTER 150 SUB LENGTH 160 BGTR LOOPEND 170 BZ LOOPEND 180 REM ВВОД В ЯЧЕЙКУ ПАМЯТИ VALUE 185 REM ОЧЕРЕДНОГО ЧИСЛА 190 IN VALUE 200 REM УВЕЛИЧЕНИЕ НА 1 СОДЕРЖИМОГО 203 REM СЧЕТЧИКА 205 REM DATA-COUNTER 210 LD COUNTER 220 ADD ONE 230 STO COUNTER 240 REM ЕСЛИ VALUE < SMALLEST 250 LD VALUE 260 SUB SMALLEST 270 BGTR ENDIF 280 BZ ENDIF 290 REM TO 300 REM ЗАМЕНИТЬ СОДЕРЖИМОЕ SMALLEST 305 REM КОПИЕЙ СОДЕРЖИМОГО VALUE 310 LD VALUE 320 STO SMALLEST 330 REM ЗАМЕНИТЬ СОДЕРЖИМОЕ 335 REM SMALLEST-POSITION КОПИЕЙ СОДЕРЖИМОГО DATA-COUNTER
Вычислительные машины простой архитектуры 47 340 LD COUNTER 350 STO POSITION 360 REM КОНЕЦ ОПЕРАТОРА IF 370 ENDIF: В LOOP 380 REM КОНЕЦ ЦИКЛА 390 REM ВЫВОД НА ПЕЧАТЬ 395 REM SMALLEST-POSITION 400 410 LOOPEND: STOP OUT POSITION 420 REM КОНЕЦ ПРОГРАММЫ 430 REM РАСПРЕДЕЛЕНИЕ ПАМЯТИ 440 LENGTH: DC 0 450 SMALLEST: DC 0 460 COUNTER: DC 0 470 ONE: DC 1 480 VALUE: DC 0 490 POSITION: DC 0 Итак, выше достаточно подробно рассмотрены две задачи и выполнено программирование на псевдокоде и языке TOYCODE, Читатели, полностью разобравшиеся в этих задачах, сделали существенный шаг в изучении программирования на языке ас- семблера. Следует, конечно, помнить, что принципы организации TOYCOM во многом подобны (хотя и в упрощенном варианте)^ принципам организации реальных ЭВМ. Знания, полученные в гл. 3, понадобятся для знакомства с реальным языком ассембле- ра вычислительной системы VAX-11, Выводы 1. Язык ассемблера удобен при решении целого ряда задач. Он практически незаменим при углубленном изучении логики работы ЭВМ. Языки ассемблера реальных машин очень сложны. В данной главе рассмотрена идеализированная, упрощенная вы* числительная машина TOYCOM со своим языком. Это сделано с целью облегчения первых шагов в изучении языка ассемблера VAX. 2. В машине TOYCOM всего 12 выполняемых команд. Ее па- мять состоит из 100 четырехразрядных ячеек десятичных чисел с адресами от 0 до 99. В центральном процессоре три основных регистра: аккумулятор для операндов и результата, регистр, Команды, в который пбмещается очередная команда для анализа'
48 Глава 1 и выполнения, и регистр счетчика команд, предназначенный для управления последовательностью выполнения команд. 3. Разработка алгоритма решения задачи может проводиться с помощью особого языка — псевдокода. Псевдокод включает специальные элементы для описания операций выбора и циклов; эти операции предполагают предварительную проверку некото- рого условия. Псевдокод допускает использование кратких опи- саний на естественном языке, например английском или русском, для записи других выполняемых операций. Псевдокод можно ис- пользовать не только при разработке программ, но и как сред- ство документирования (комментирования) в программах на языке ассемблера. 4. Наиболее широко используемый принцип организации ра- боты ЭВМ заключается в том, что программы выполняются по- сле загрузки в оперативную память. При этом ячейки памяти, содержащие команды, и ячейки памяти, содержащие данные, для процессора оказываются неразличимыми. 5. Вычислительные машины обрабатывают встречающиеся команды, выполняя одну и ту же простую циклически повторяю- щуюся последовательность операций. Одной из частей этого цик- ла является извлечение команды из памяти и загрузка ее в ре- гистр команд. Другой составной частью цикла является выпол- нение этой команды. 6. Программирование непосредственно в машинных коман- дах имеет два недостатка. Во-первых, программистам трудно оперировать с кодами операций и адресами, потому что все они представляются в числовой форме. Во-вторых, в командах пере- хода используются абсолютные машинные адреса, что услож- няет процесс внесения изменений в программы. 7. В языке ассемблера TOYCODE машины TOYCOM преду- смотрено символическое именование кодов 12 имеющихся ма- шинных команд. В дополнение к этому в языке TOYCODE име- ются еще две директивы — DC и REM. 8. Преобразование алгоритма решения задачи, описанного псевдокодом, в запись программы на языке TOYCODE может быть выполнено по вполне определенным правилам. Если при- держиваться этих правил при перекодировке операторов пере- дачи управления из псевдокода в TOYCODE, то программа на ассемблере оказывается достаточно хорошо структурированной. Новые термины Аккумулятор Ассемблер Безусловный переход Ввод с указанием признака конца вводимых элементов
вычислительные машины простой архитектуры 49 Ввод с указанием числа вводимых элементов Выполняемая команда Директивы Инверсия условия Интерпретатор Код операции Компилятор Машина с запоминаемой программой Операнд Оператор выбора Программа, модифицирующая собственную структуру Псевдокод Регистр команд Режим реального масштаба времени Счетчик команд Условный переход Центральный процессор Цикл выборки — исполнения Цикл с предварительной проверкой условия Чистый интерпретатор Язык машинных команд Вопросы и упражнения 1. В чем заключаются два главных преимущества использо- вания языка ассемблера по сравнению с машинными коман- дами? 2. Преобразуйте следующие логические условия так, чтобы все переменные оказались с левой стороны от знака операций отношения (<, = и т. д.). a) N + 1 < SUM б) N + 2 = TOT в) С < = NVALUES г) SMALL < VALUE д) SUMPOS > = TOTAL - 47 3. Определите условия, обратные заданным в п. 2, и после этого преобразуйте их так, чтобы все переменные оказались с левой стороны от знака операции отношения. Для следующих задач выполните описание алгоритма решения задачи на псевдокоде, преобразуйте текст на псевдокоде в текст на языке TOYCODE и тщательно проверьте получившиеся про- граммы.
60 Глава 1 4. Исходные данные: число LENGTH и следующая за ним последовательность чисел. Количество чисел в последовательно- сти равно LENGTH. Искомый результат: сумма введенных чисел. 5. Исходные данные: последовательность отрицательных чи- сел, завершающаяся нулем. Искомый результат: количество чисел, равных —3, в исход- ной числовой последовательности. 6. Исходные данные: последовательность не равных нулю чи- сел, завершающаяся нулем. Искомый результат: среднее арифметическое исходных чисел. 7. Исходные данные: число LENGTH и следующая за ним последовательность чисел. Количество чисел в последовательно- сти равно LENGTH. Искомый результат: количество положительных чисел (в про- центах) в исходной числовой последовательности. 8. Исходные данные: число LENGTH и следующая за ним последовательность чисел, значением каждого из которых явля- ется возраст служащих некоторого предприятия. Количество вводимых чисел равно LENGTH. Искомый результат: число служащих, возраст которых пре- вышает 39 лет. 9. Исходные данные: три целых числа. Искомый результат: исходные числа, расположенные в по- рядке убывания их значений. 10. Исходные данные: несколько групп чисел. Каждая группа состоит из трех положительных чисел. За каждой группой сле- дует число —1. Каждое из чисел в группе представляет длину стороны некоторого треугольника. В каждой группе на первом месте расположено наибольшее число. Искомый результат: номера групп, элементы которых — сто- роны прямоугольного треугольника. Как известно, у прямоуголь- ного треугольника квадрат длины наибольшей стороны равен сумме квадратов длин двух других сторон. 11. Исходные данные такие же, как и в предыдущей задаче. Однако наибольшее число в каждой группе может быть на лю- бом месте: первом, втором или третьем. Искомый результат такой же, как и в задаче п. 10. 12. Исходные данные: число LENGTH и следующая за ним последовательность пар чисел. Количество пар в последователь- ности равно числу LENGTH. Каждая пара состоит из числа успешных бросков и числа промахов подающего мяч в баскет- больной команде. Оба числа относятся к определенному году или сезону игры. Искомый результат: а) количество (в процентах) успешных бросков данного подающего за все рассматриваемые годы}
Вычислительные машины простой архитектуры 51 б) число лет, в которые количество успешных бросков было бо- лее 50 %. 13. Исходные данные: положительное целое число, меньшее 8. Искомый результат: факториал заданного числа, определяе- мый следующим образом: factorial (N) = N • factorial (N — 1) factorial (0) = factorial (1) = 1 14. Исходные данные: положительное целое число TOTAL» меньшее 20. Искомый результат: первые TOTAL чисел последовательно- сти Фибоначчи, определяемой следующим образом: первыми тре- мя числами последовательности являются 1, 1 и 2. Каждое По- следующее число в последовательности определяется как сумма двух предыдущих чисел.
Глава 2 Арифметика недесятичных чисел Появление и широкое использование десятичной системы счис- ления, несомненно, связано с тем, что у человека имеется десять пальцев на руках. Для вычислительных машин, конечно, это ни- какого значения не имеет. Представление чисел внутри ЭВМ определяется характеристиками элементов, из которых состоит память машины. Наиболее дешевые запоминающие устройства получаются на элементах с двумя устойчивыми состояниями. Поэтому для представления чисел внутри ЭВМ в наибольшей степени подходит двоичная система счисления, или система счис- ления с основанием 2. При обработке операторов языков высокого уровня всегда автоматически выполняется преобразование исходных чисел из десятичной системы счисления в двоичную. При выводе данных выполняется обратное преобразование из двоичной системы в десятичную. Это освобождает программистов, использующих языки высокого уровня, от необходимости работы с двоичными числами. Языки ассемблера таких услуг не предоставляют. Про- граммист, использующий язык ассемблера, кроме двоичной си- стемы счисления должен также знать некоторые другие совме- стимые (согласованные) с ней системы счисления. При выводе данных из оперативной памяти их обычно группируют с целью представления в другой, более удобной системе счисления. Хо- рошо согласованными с двоичной являются системы счисления с основаниями 2Л, где п — целое положительное число. При этом обеспечивается достаточно простое преобразование записи числа при переходе из одной системы счисления в другую. В большин- стве случаев в качестве такого основания выбирают число 16. Система счисления с основанием 16 называется шестнадцатерич- ной. В ряде случаев используется и восьмеричная система счис- ления (с основанием 8). В данной главе рассматриваются форма записи, правила сложения и вычитания чисел в двоичной и шест- надцатеричной системах счисления, а также алгоритмы преобра- зования десятичных, двоичных и шестнадцатеричных чисел в эк- вивалентные значения в других системах счисления. Материал этой главы безусловно необходим для чтения следующих глав книги.
Арифметика недесятичных чисел 53 2.1. Позиционные системы счисления Десятичная система счисления является одной из так называе- мых позиционных систем счисления. В таких системах положе- ние каждой цифры имеет существенное значение в представле- нии числа. Роль положения цифр становится особенно ясной при записи числа в полиномиальной форме. Иногда не обращают должного внимания на то, что при использовании позиционной системы счисления величина числа оценивается значением неко- торого полинома, коэффициентами которого являются отдельные цифры в записи этого числа. Например, десятичное число 342 можно представить в виде полинома (3-102)4-(4-10°), или (3 100)4-(4-10)4-(2-1). Не все системы счисления, которыми пользовалось человече- ство, были позиционными. Наиболее ярким примером непозици- онной системы счисления является римская система счета. В римской системе для обозначения разных десятичных разря- дов (10п) используются разные символы. Положение символа в записи числа с его величиной не связано непосредственно, хотя положение символа относительно других символов является важным 1). Например, символ X обозначает 10 вне зависимости От его конкретного положения в строке символов, представляю- щих число. Непозиционные системы счисления неудобны и для ;людей, и для ЭВМ и, как правило, не используются. В этой главе рассматриваются двоичная и шестнадцатеричная системы. Они являются позиционными системами. Поэтому запись чисел в этих системах очень похожа на привычную нам десятичную за- пись. Изучить правила выполнения операций над такими чис- лами тоже относительно не трудно, особенно если их постоянно сравнивать с известными правилами для десятичных чисел. 2.2. Двоичные и шестнадцатеричные системы счисления Значение числа, положенного в основание системы, равно коли- честву различных символов (или цифр), необходимых для записи чисел в этой системе. Основанием десятичной системы счисления является число 10. В соответствии с этим в данной системе используется десять разных цифр от 0 до 9. Основанием двоичной системы является число 2. Поэтому в этой системе для записи чисел используются две различные цифры. Для этой цели пригодны, конечно, любые два символа, но наиболее естественно ° В системе римских цифр символы I, X, С, М используются для обо- значения 10°, 101, 10* и 10s соответственно, а символы V, L и D —для обо- Йачения 5, 50 и 500. Эти символы называют римскими цифрами. Если ббльшая цифра стоит перед меньшей, то величина числа определяется сложе- ?ием их значений, если же — меньшая перед большей, тб — вычитанием. 1рим. рвд.
54 Глава 2 воспользоваться двумя младшими цифрами десятичной систе- мы— 0 и 1. Таким образом, число в двоичной системе представ- ляется последовательностью символов из множества {0, 1}. Дво- ичная система является позиционной: появление нуля или еди- ницы в том или ином месте последовательности существенно при определении величины числа. Например, двоичное число 1011 можно записать как полином: (1-23)Н-(0-22) + (1+ и-2°), или (1 •8) + (0-4) + (1 •2)-|-(1 • 1), что соответствует числу 11 в десятичной системе. Последовательный счет в десятичной системе сводится к пере- бору всех цифр десятичной системы — от 0 до 9. После этого слева добавляется еще одна позиция. В нее помещается цифра 1 и опять осуществляется последовательный перебор десяти цифр в правой позиции. Аналогичные действия повторяются и дальше. Подобным же образом ведется счет и в двоичной системе. Отли- чие только в том, что цикл перебора всех цифр любой позиции выполняется быстрее, поскольку вместо десяти используется всего два отличающихся друг от друга символа. Для первых 20 чисел имеется следующее соответствие между их десятичным и двоичным представлением: Десятичное представление числа Двоичное представление числа Десятичное представление числа Двоичное представление числа 0 0 и 1011 1 1 12 1100 2 10 13 1101 3 11 14 1110 4 100 15 1111 5 101 16 10000 6 по 17 10001 7 111 18 10010 8 1000 19 10011 9 1001 20 (0100 10 1010 При анализе машинных команд и обрабатываемых данных часто приходится определять значения отдельных цифр, или би- тое (сокращенное от английского Binary digIT — двоичная циф- ра). Однако анализировать длинные последовательности цифр при двоичном представлении числа не очень удобно, и поэтому
Арифметика недесятичных чисел 5S коды, подлежащие выводу из ЭВМ, обычно переводят в некото- рую систему счисления, согласованную с двоичной. В первые годы развития вычислительной техники в качестве такой систе- мы чаще всего использовалась восьмеричная система (с основа- нием 8). Однако с появлением в 60-х годах вычислительной си- стемы IBM/360 стала широко использоваться шестнадцатерич- ная система. В IBM/360 размер участков оперативной памяти исчисляют в байтах, состоящих из 8 двоичных цифр. В байтах измеряют длины кодов операций и строк символов; байт являет- ся основной адресуемой единицей памяти. Использование в ка- честве единицы измерения памяти 8 двоичных цифр, а, напри- мер, не 6, объясняется тем, что комбинациями из 6 двоичных цифр можно представить 64 разных символа, в то время как только для работы с прописными и строчными буквами латин- ского алфавита требуется 52 символа. Поскольку байт определен как адресуемая область памяти из 8 двоичных разрядов, а каж- дая цифра (0—7) восьмеричного представления чисел описы- вается тремя двоичными разрядами (ООО—111), восьмеричная система не является согласованной с системой записи побайтно. (Восемь не делится на три без остатка.) Если увеличивать осно- вание системы счисления, то ближайшей, согласованной с двоич- ной, оказывается шестнадцатеричная система. Она хорошо со- гласуется также с представлением чисел байтами, поскольку одна шестнадцатеричная цифра описывается четырьмя битами. Для представления 8 двоичных цифр требуется ровно две шест- надцатеричные цифры. Во многих ЭВМ, созданных после IBM/360, также в качестве адресуемой единицы памяти исполь- зуется байт, равный 8 двоичным разрядам, и поэтому шестна- дцатеричная система счисления чисел стала основной в програм- мировании на языках ассемблера. Для записи чисел в шестнадцатеричной системе требуется 16 различных символов, представляющих ее цифры. В системах счисления с основанием меньшим, чем наиболее привычное нам основание 10, в качестве цифр используются знакомые символы десятичной системы. Однако для шестнадцатеричной системы требуются символы еще для шести дополнительных цифр. С этой целью можно, конечно, использовать любые шесть символов, но лучше всего воспользоваться символами, которые уже некоторым естественным образом упорядочены. Исходя из этого в качестве дополнительных шести символов обычно выбирают первые шесть букв алфавита. Это удобно, во-первых, потому, что не требуется введения новых, непривычных, символов и, во-вторых, поскольку буквам присуща естественная упорядоченность. Таким образом, в шестнадцатеричной системе используются цифры; 0, 1, ,,,, 9, А, В, С, D, Е, F. Можно, конечно, возразить, что запись чисел с использованием этих символов выглядит достаточно необычно.
56 Глава 2 однако еще более непривычной была бы запись с использова- нием букв греческого алфавита или каких-нибудь других незна- комых символов. Последовательное перечисление чисел в шестнадцатеричной системе проводится точно так же, как в десятичной или двоич- ной системах. Если счет ведется от 0, то сначала последователь- но перечисляются все цифры системы, а затем вводится еще одна позиция для старшего разряда слева от текущей позиции. Шестнадцатеричные и двоичные эквиваленты десятичных чисел от 0 до 20 имеют следующий вид: Числа Числа Десятичные Двоичные Шестна- дцате- ричные Десятичные Двоичные Шестна- дцате- ричные 0 0 0 11 1011 в 1 1 1 12 1100 с 2 10 2 13 1101 D 3 11 3 14 1110 Е 4 100 4 15 1111 F 5 101 5 16 10000 10 6 по 6 17 10001 11 7 111 7 18 10010 12 8 1000 8 19 10011 13 9 1001 9 20 10100 14 10 1010 А Можно заметить, что в момент перехода от представления числа одним шестнадцатеричным символом к представлению двумя символами (при переходе от F к 10) в двоичном пред- ставлении число используемых разрядов также увеличивается с четырех до пяти. Это является косвенным подтверждением взаи- мосвязи двоичной и шестнадцатеричной систем счисления. Числа, представляемые одной шестнадцатеричной цифрой, точно описы4 ваются четырьмя эквивалентными двоичными цифрами. 2.3. Сложение и вычитание чисел 2.3.1. Сложение Рассмотрим выполнение операций сложения и вычитания в дво- ичной и шестнадцатеричной системах счисления. Эти операции выполняются по одним и тем же правилам независимо от
Арифметика недесятичных чисел 57 системы счисления, и потому их изучение не должно оказаться трудным. Алгоритм сложения двух чисел в произвольной системе счис- ления может быть описан следующим образом (алгоритм пре- образования двоичных чисел в десятичные рассматривается в разд. 2.4): Установить указатель текущего разряда складываемых чисел над цифрой, крайней справа. WHILE указатель расположен над цифрой хотя бы одного из чисел DO Сложить цифры под указателем (возможно с учетом дополнительной 1, полученной в результате переноса из младшего разряда) IF сумма величине основания системы счисления THEN Записать правую цифру суммы под складываемыми цифрами Над следующим расположенным слева разрядом записать 1 ELSE Записать сумму под складываемыми цифрами ENDIF Передвинуть указатель текущего разряда на одну позицию влево END-DO Конец программы Применим этот алгоритм к десятичным числам 127 и 13. Вы- полнение алгоритма по шагам цикла WHILE можно предста- вить в следующем виде: Шаг: 1 2 3 4 1 г 1 г 1 1 127 127 127 127 _ 13 _ 13 13- 13 0 ‘ 40 ’ ’ 140 *> В частном случае у складываемых чисел очередной старший разряд может отсутствовать. — Прим, перед.
Глава 2 Применим этот же алгоритм к двоичным числам 1001 и 10h Шап 1 2 3 4 5 4 4 4 1 1 1 1 1001 1001 1001 1001 1001 / 101 101 101 101. юг 0 - 16 110 1110 В двоичной системе сумма двух единиц равна 10, т. е. вели* чине основания системы. Результат такого суммирования вызы- вает перенос единицы в следующий разряд. Имеется смысл про- верить правильность полученного результата. Запишем десятич- ные эквиваленты исходных чисел и суммы! 1-8+ 0«4 + 0-2 +1«1 «9 1»4 + 0’2 + 1’1 <= 5 1*8 + 1’4 + 1*2 + 0« 1 «= 14« В Как видно, сумма вычислена верно. Рассмотрим еще один пример: Шаг; 1 1 3 4 4 г 4 4 1 и ш 10111 101П 10111 10111 1011 1011 1011 1011 0 10 010 5 6 7 J- 4 1111 11111 11111 10111 10111 юш 1011 1011- 1011 0010 00010 100010 В данном случае 101112 = 23ю 1), 10112 = Ню и 1000102 =] [₽= 3410- Выполнение тех же операций в десятичной системе опять показывает, что алгоритм работает безошибочно. * » »— *> Для сокращения записи в соответствии с принятой практикой справа рт числа в виде нижнего индекса будет указываться основание используемой Системы счисления, — Прим, перев.
Арифметика недесятичных чисел 5д Применим этот же алгоритм к шестнадцатеричным числам 70В и 16: Шаг; 1 2 3 4 J- г 1 Ф 1 1 1 70В 70В 70В 70В 16 16 16 16 1 21 721 Как видно, выполнить эти операции несколько сложнее, чем сложение двоичных чисел. В двоичной системе сумма, равная 10 или 11, получается при сложении, соответственно двух или трех единиц. Выполнить такое сложение проще, чем сложить два шестнадцатеричных числа. В шестнадцатеричной системе В + 6 = 11, однако на первый взгляд это не столь очевидно, как сложение двух единиц в двоичной системе. Для сложения двух шестнадцатеричных цифр оказывается удобным мысленно заме- нить их десятичными эквивалентами и затем выполнить сложе- ние десятичных чисел. Например, для расчета В16 + би вычис- лить 11 ю+ 6ю и получить результат в виде 17ю. Поскольку 17 больше 16 (основания шестнадцатеричной системы), то при вы- читании 16 из 17 получим 1 в младшем разряде и 1 переноса в старший разряд шестнадцатеричного представления десятичного числа 17. Подобные преобразования нужны только для шестна- дцатеричных чисел А, В, ..., F, десятичными эквивалентами ко- торых являются числа 1О,о, Ню, ..., 15,о- Достаточен неболь- шой опыт, чтобы выполнение этих преобразований не вызывало затруднений. Прежде чем перейти к следующему примеру, проверим пра- вильность результата в первом рассмотренном примере сложения шестнадцатеричных чисел. 70В,6 = 710 • 25610 + 11,о= 1792,о + Н,о = 1803,0, 16ю = 1 • 16,о + 6,о = 22,0, 721,6 = 7,о • 256,о + 2,о • 16,о + 1 = 179210 + 32,0 + 1 = 1825,0 Следовательно, суммирование выполнено правильно. Теперь рассмотрим сложение чисел 1A7F и 535; Шаг: 1 а 3 4 5 1 г 1 Г 1 1 1А7В 1A7F 1A7F 1A7F 1A7F , 535 _ 535 535 _ 535 535, 4 В4 ш •1ш'
60 Глава 2 Сложение выполнено правильно, поскольку 1A7F16 = 6783ю, Б3516 = 133310, 1FB4i6 = 811610 и 678310 + 1333ю = 8116ю. Что- бы приобрести опыт в выполнении сложения в трех рассмотрен- ных системах счисления, целесообразно выполнить соответствую- щие упражнения, приведенные в конце данной главы. 2.3.2. Вычитание Как выполнять операцию вычитания десятичных чисел, известно всем. Как и сложение, вычитание чисел в произвольной системе счисления полностью подобно вычитанию десятичных чисел. Приведем алгоритм операции вычитания. Как и в алгоритме сложения, здесь предполагается известным правило выполнения рассматриваемой операции над цифрами одного разряда. Установить указатель текущего разряда вычитаемых чисел над цифрой, крайней справа. WHILE указатель расположен над цифрой DO IF цифра вычитаемого цифры уменьшаемого в данном разряде THEN Вычесть цифру вычитаемого из цифры уменьшаемого в данном разряде Записать разность под цифрой вычитаемого в данном разряде ELSE Занять единицу из цифры ближайшего слева разряда уменьшаемого Цифру уменьшаемого в данном разряде заменить на сумму этой цифры и величины основания системы Вычесть цифру данного разряда вычитаемого из указанной выше суммы Разность записать под цифрой вычитаемого в данном разряде ENDIF Передвинуть указатель текущего разряда на одну позицию влево END-DO Конец программы Данный алгоритм применим к числам любой системы счисле- ния, Единственное затруднение может быть связано с тем, что
Арифметика недесятичных чисел 61 не было определено точно, что значит «занять единицу». А это по авторитетному мнению любого школьника является самым трудным в вычитании. Поясним эту операцию на привычной для нас десятичной системе счисления. Занять единицу очень про- сто у любой цифры, большей нуля. Для этого нужно только вы- честь 1 из цифры следующего старшего разряда числа, а к циф- ре данного разряда прибавить величину основания системы. Ес- ли же в том разряде, откуда должна быть взята 1, находится О, то необходимо обратиться к следующему по старшинству раз- ряду, пока не встретится первая, отличная от 0, цифра. Именно из нее следует вычесть единицу, а все «пройденные» ранее нули нужно заменить старшей цифрой данной системы счисления (цифрой 9 в десятичной системе, цифрой 1 — в двоичной и F — в шестнадцатеричной). После этого к цифре рассматриваемого разряда остается прибавить величину основания системы. Рассмотрим работу этого алгоритма на примере чисел. Пусть требуется вычесть 53 из 424: Шаг: 1-234 ,424 424 3(12)4 3(12)4 53 . 53 53 53 1 71 371 Здесь запись (12) означает новое содержимое разряда после переноса («заимствования») единицы из старшего разряда уменьшаемого. Применим этот же алгоритм к двоичным числам. Выполним, в частности, вычитание 101 из 1011: Шаг: 1. 2 3 4 1 I- -1 -I 1011 1011 1011 (2)11 101 101 101 101 0 10 по Как и в предыдущем примере, в скобках указано новое со- держимое данного разряда после переноса единицы из старшего разряда. Хотя эта величина и приводится в десятичной системе счисления, она должна соответствовать одному разряду числа. В качестве еще одного примера вычислим разность 10001г—- -112:
62 Глава 2 Шаг: » 2 3 4. 5 ф 10001 10001 *П(2)1 11(2)1 11(2)1 11 и _ 11 11 i 11 0 10 ' 116 1110 Вычитание шестнадцатеричных чисел выполняется аналогич- но, хотя по сравнению с вычитанием десятичных чисел выглядит несколько необычно. Вычислим сначала разность 29В16—A4<l6: Шаг: 1 2 3 4 Ф 29В 29В 1(25)В 1(25)8 А4 А4 А4 А4 7 Г7 1F7 Как и при сложении шестнадцатеричных чисел, цифры одно- именных разрядов рассматриваемого разряда удобно предвари- тельно перевести из шестнадцатеричной системы в десятичную. В частности, в этом примере удобно вычислять Пю—4ю, а не В16—416. Значение второго разряда, уменьшаемого после пере- носа в него единицы из старшего разряда, представляется двумя десятичными цифрами, а именно 25. И в этом случае предпочти- тельный способ расчета заключается в преобразовании 1916 в 2510, вычислении разности десятичных чисел 25—10 = 15 с по- следующим переводом в шестнадцатеричную форму, результа- том чего будет одноразрядное число F. В приведенном выше примере состояние разрядов уменьшаемого после переноса еди- ницы из старшего разряда описано с помощью шестнадцатерич- ных и десятичных цифр. Однако, поскольку последние всегда заключаются в скобки, ошибочное понимание невозможно. Рассмотрим еще один пример вычитания шестнадцатеричных чисел. Шаг: 1 2 3 4 г 1 1001 ГГ(17) ВД] FF(17) 52 52 .52 52 В AF' ГАВ Проверка: 1001,6 = 409610 + 1 = 409710, 5216 = 80ю + 2ю = 8210, FAF16 = 384010 + 16010 + 15w = 40151О.
Арифметика недесятичных чисел 63 Для закрепления навыков работы с числами, представлен- ными в различных системах счисления, полезно выполнить не- сколько упражнений на вычитание, приведенных в конце главы. 2.4. Преобразование чисел при переходе из одной системы счисления в другую Рассмотрим правила преобразования формы представления чи- сел при переходе из одной системы счисления в другую. При проведении таких преобразований приходится обычно выполнять много простых арифметических операций, что оказывается весь- ма утомительным для человека. (Если бы это было не так, век ЭВМ, наверное, еще долго бы не наступил.) При выполнении этих преобразований требуется особое внимание. 2.4.1. Представление чисел в десятичной системе счисления Ниже приводится написанный на псевдокоде алгоритм преобра- зования числа, представленного в любой возможной системе счисления, в запись его в десятичной системе *>. Встречающиеся в алгоритме арифметические операции выполняются над деся- тичными числами. Поэтому это преобразование выполнять отно- сительно не сложно. Установить указатель текущего разряда числа над цифрой, крайней слева. Переменной RESULT присвоить начальное значение, равное величине, определяемой цифрой в текущем разряде. Передвинуть указатель на одну позицию вправо. WHILE указатель расположен над цифрами DO Умножить значение RESULT на (выраженную в десятичной системе счисления) величину основания данной системы. (Произведение помещается снова в RESULT.) К хранящемуся в RESULT значению добавить десятичное число, эквивалентное по величине цифре текущего разряда Передвинуть указатель на одну позицию вправо END-DO Конец программы Речь идет о записи в десятичной системе счисления любого числа, пред* ставленного в какой-либо позиционной системе счисления двоичной, восьме* ричной, шестнадцатеричной и т. п, — Прим. ред.
64 Глава 2 В качестве первого примера рассмотрим перевод двоичного числа 10110 в десятичную систему: 1 10110 1 х2 2 4-0 2 1 юно х2 ’ 4 4-1 5 юно х2 10 4-1 11 1 юно х2 22 4-0 22 юно Применим этот алгоритм к преобразованию шестнадцатерич ного числа 3F7: I 3F7 Result: 3 Х16 48 14-15 63 3F7 X16 1008 4-7 J015 4 ЗЕТ
Арифметика недесятичных чисел 65 2.4.2. Преобразование двоичных чисел в шестнадцатеричные и шестнадцатеричных чисел в двоичные Для преобразования двоичных чисел в шестнадцатеричные нуж- но знать шестнадцатеричные эквиваленты всех возможных четы- рехразрядных чисел: Числа Двоичные Шестнадцате- ричные Двоичные Шестнадцате- ричные 0000 0 1000 8 0001 1 1001 9 0010 2 1010 А ООН 3 1011 В 0100 4 1100 С 0101 5 1101 D оно 6 1110 Е 0111 7 1111 F Требуемое преобразование выполняется следующим образом. Все цифры двоичной записи числа, начиная справа, разбиваются на группы по 4. Если в самой левой группе окажется меньше че- тырех цифр, слева следует приписать столько нулей, сколько не- обходимо для получения полной группы из 4 цифр. Далее в со- ответствии с приведенной выше таблицей каждая группа из 4 двоичных разрядов заменяется своим шестнадцатеричным эк- вивалентом. В результате получается шестнадцатеричный экви- валент исходного двоичного числа. Например, в двоичном числе 10111100111 могут быть выделены следующие 4-разрядные груп- пы: 0101, 1110 и 0111. Поэтому эквивалентом заданного двоич- ного числа является шестнадцатеричное число 5Е7. Преобразование шестнадцатеричных чисел в двоичные совер- шается в обратном порядке. Каждая из шестнадцатеричных цифр просто заменяется своим четырехразрядным двоичным эк- вивалентом. При этой замене, конечно, можно пользоваться при- веденной выше таблицей соответствия чисел разных систем счисления. Например, отдельным разрядам шестнадцатеричного числа 3F7A соответствуют четырехразрядные двоичные числа ООП, 1111, 0111 и 1010. Поэтому двоичным эквивалентом всего числа будет 0011111101111010, 3 Зак. 483
66 Глава 2 2.4.3. Преобразование чисел в недесятичные системы счисления Обычно при переводе десятичного числа в недесятичную систему счисления требуется выполнить больше операций по сравнению с аналогичными преобразованиями из других систем счисления. Как следствие, вероятность возникновения ошибки в этом слу- чае выше. По существу, необходимо выполнить обратные дей- ствия по отношению к преобразованию недесятичных чисел в де- сятичные. Если при преобразовании недесятичного числа в де- сятичное выполняется умножение на величину основания исход- ной системы счисления, то теперь потребуется выполнить деле- ние на величину основания системы, в которой число должно быть представлено. Процесс преобразования числа из десятичной системы счис- ления в любую другую позиционную систему может быть запи- сан на псевдокоде следующим образом: Присвоить значение преобразуемого десятичного числа переменной ДЕЛИМОЕ WHILE ДЕЛИМОЕ > О DO Разделить ДЕЛИМОЕ на величину основания системы, в которую осуществляется перевод Заменить ДЕЛИМОЕ частным Остаток от деления (выраженный цифрой системы, в которую осуществляется перевод) помес- тить в СПИСОК END-DO Напечатать цифры СПИСКА в обратном порядке Конец программы Заметим, что СПИСОК хранится в памяти ЭВМ, например, в форме массива. Применим этот алгоритм для преобразования десятичных чи- сел 79 и 64 в эквивалентные двоичные. (Необходимо следить за тем, чтобы процесс преобразования не был прекращен прежде- временно). 2|79 2|39 Остаток = 1, 2| 19 Остаток =1, 2|9 Остаток =1, 2|64 2|32 Остаток = О, 2| 16 Остаток = 0. 2| 8 Остаток = 0:
Арифметика недесятичных чисел 67 2|_4 Остаток =1, 2| 2 Остаток = О, 2| 1 Остаток = О, О Остаток =1, Результат: 1001111. 2|_4 Остаток = 0, 2|_2 Остаток = 0, 211 Остаток = 0, 0 Остаток = 1. Результат: 1000000. С помощью этого алгоритма преобразуем десятичное число 1471 в шестнадцатеричное: 16|1471 16|91 Остаток = F, 16[5 Остаток = В, 0 Остаток = 5. Результат: 5BF Чтобы выполнить эти преобразования, необходимо распола- гать бумагой, карандашом и временем, еще требуется немного удачи, чтобы результат деления чисел на 16 был безошибочным. Целесообразнее предварительно перевести исходное число в двоичную систему или воспользоваться таблицей соответствия десятичных и шестнадцатеричных чисел. Такая таблица приве- дена в приложении В. Поскольку программистам часто необходимо выполнять пре- образование чисел из одной системы счисления в другую, эти функции (для десятичной, шестнадцатеричной, восьмеричной и двоичной форм представления) включены в набор операций, вы- полняемых некоторыми карманными калькуляторами. 2.5. Представление отрицательных чисел в дополнительном коде Целые числа в памяти ЭВМ хранятся в двоичной форме. Если данные, с которыми работает ЭВМ, представляют собой 2-байто- вые (16-битовые) целые числа, то для их хранения в памяти машины требуется 16 бит. Специально следует рассмотреть вопрос о способах хранения отрицательных чисел в таких 16-битовых «словах» памяти. Один из способов заключается в выделении отдельного двоичного раз- ряда для хранения знака числа. При этом остальная часть «сло- ва» будет использоваться для хранения абсолютной величины
68 Г лава 2 этого числа. Такой способ представления числа внутри ЭВМ на- зывается способом представления величиной и знаком. Именно так обычно записываются десятичные числа на бумаге. ЭВМ, однако, работает эффективнее при использовании дру- гой формы представления отрицательных целых чисел. Ряд пер- вых вычислительных машин, а также некоторые модели совре- менных ЭВМ для хранения отрицательных чисел используют так называемый обратный код двоичного числа. Его получают, выполняя поразрядную инверсию соответствующего положитель- ного двоичного числа. Поразрядная инверсия есть операция за- мены содержимого каждого разряда на противоположное по значению (все единицы становятся нулями, а все нули — едини- цами). Эта форма представления отрицательных чисел вполне пригодна, если для хранения абсолютной величины двоичного числа достаточно количества двоичных разрядов, на единицу меньшего того, которое предоставляется двоичным числом дан- ного типа (размером байт, слово, двойное слово и т. п.). Напри- мер, если для хранения двоичного числа выделено 8 двоичных разрядов (поле размером байт), то для хранения абсолютной величины числа предоставляется 7 двоичных разрядов. В таком случае числа 5 и —5 будут представлены в следующем виде: 5:00000101 -5: 11111010 Однако описанному представлению чисел присущ один не- достаток: нуль имеет две формы представления: 0:00000000 и -0: 11111111 В ЭВМ, использующей такую форму представления чисел, требуются дополнительные схемы для работы с обеими разно- видностями нуля. Во избежании этого в большинстве современ- ных ЭВМ отрицательные числа представлены несколько иначе, а именно дополнительным кодом. Этот код получается, если к содержимому младшего разряда обратного кода прибавить 1. Например, число —5 в дополнительном коде имеет следующий вид; 5: 00000101 Обратный код: 11111010 Добавление 1: +1 Дополнительный код: 11111011 Обратный переход от дополнительного кода числа к его двоич- ному представлению (к абсолютной величине числа) выпол- няется с помощью тех же самых операций, что и при формиро- вании дополнительного кода. В частности, чтобы определить аб-
Арифметика недесятичных чисел 69 солютную величину числа, записанного в дополнительном коде, следует выполнить его поразрядную инверсию и затем приба- вить 1. В частности, абсолютное значение отрицательного числа —5 получается следующим образом: Дополнительный код: 11111011 Поразрядная инверсия: 00000100 Добавить 1: 4-1 Абсолютное значение: 00000101 Таким же способом может быть получено абсолютное значе- ние для любого отрицательного числа, записанного в дополни- тельном двоичном коде. Преобразование чисел из двоичной си- стемы в десятичную следует начинать с анализа значения цифры самого старшего (левого) разряда. Если это значение равно нулю, то число — положительное; его можно непосредственно переводить в десятичную форму. Если же это значение равно 1, то число — отрицательное, поэтому следует его сначала переве- сти в дополнительный двоичный код, результат преобразовать в десятичную форму, снабдив его знаком «минус». Рассмотрим следующий пример: Исходное двоичное число: ПОПОЮ Поразрядная инверсия: 00100101 Добавление 1: 00100110 Абсолютная величина: 38 Десятичное представление исходного числа- —38 Создатели первых ЭВМ тратили много сил на поиск наибо- лее простых логических схем для выполнения операций. При этом было, в частности, обнаружено, что вычитание эквивалент- но сложению уменьшаемого с вычитаемым, предварительно за- писанным в виде отрицательного числа. В машине операция по- разрядной инверсии выполняется очень просто. Поэтому эту опе- рацию с последующим сложением используют для выполнения вычитания. Можно отметить, что преимущества представления отрицательных чисел в дополнительном двоичном коде связаны исключительно с машинной реализацией. Для тех, кто начинает программировать на языке ассемблера, такая форма представ- ления может оказаться трудной в изучении, а поэтому не эффек- тивной при применении. Однако она используется, потому что повышает эффективность работы ЭВМ.
70 Глава 2 В качестве примера рассмотрим вычитание Юю из 54ю при записи этих чисел в восьмиразрядном двоичном коде: 00110110 (5410) —00001010 (1010) Вычитаемое, представленное как отрицательное число в до- полнительном коде, имеет вид 11110110. Поэтому операция мо- жет быть записана в виде: 00110110 + 11110110 100101100 Поскольку используется представление чисел восемью двоич- ными цифрами, цифра крайнего слева разряда результата мо- жет быть отброшена. Таким образом, правильным ответом яв- ляется 001011002=44ю. Следует помнить, что над любыми целыми двоичными чис- лами, хранящимися в памяти или регистрах, у которых в левом разряде находится 1, для определения абсолютного десятичного значения предварительно должна быть выполнена операция пре- образования в дополнительный код. Поскольку в системе VAX данные, хранимые в регистрах и памяти, представляются в шестнадцатеричной форме, определение знака числа должно вы- полняться по значению содержимого его старшего шестнадцате- ричного разряда. Все значения содержимого этого разряда, боль- шие 7, соответствуют наличию единицы в крайнем слева двоич- ном разряде. Поэтому любое число, начинающееся одной из этих шестнадцатеричных цифр, является отрицательным и хранится в дополнительном коде Ч Выводы 1. В повседневной практике (а также в примерах гл. 2) ши- роко используется представление чисел в той или иной пози- ционной системе счисления. 2. Алгоритмы сложения и вычитания могут быть записаны на псевдокоде. Эти алгоритмы не зависят от основания системы счисления, в которой представляются числа. о Имеются в виду следующие шестнадцатеричные цифры: 8, 9, А, В, С, D, Е и F. — Прим, редЛ
Арифметика недесятичных чисел 71 3. Перевод чисел из одной системы представления в другую является достаточно трудоемким. Исключение составляет только перевод чисел в систему, в определенном смысле совместимую с исходной, например перевод из двоичной системы в шестнадца- теричную. К сожалению, десятичная система не совместима ни с одной из этих двух используемых в вычислительной технике систем. 4. В большинстве современных ЭВМ отрицательные целые числа хранятся в дополнительном двоичном коде, поскольку при этом намного более простым оказывается выполнение операции вычитания. Новые термины Двоичные числа Дополнительный код Обратный код Позиционные системы счисления Поразрядная инверсия Система счисления, совместимая с двоичной системой Шестнадцатеричные числа Вопросы и упражнения 1. Выполнить следующие действия: а. 101010 б. 10111 в. 10000 г. 1010 + ПОР +И0 +1Ю0 + ши д. 110011 е. 100100 ж. 111000 з. 1100 - 111 - 101 - 11 -'1001 2. a. 1FB3 б. АВС в. 1С9 г. 4F01 + 133 +393 + F18 +FFF д. 200А е. 44FE ж. 107А з. 77АА — 14 — F01 — 52С —856 3. Выполните преобразование следующих двоичных чисел в десятичные (в предположении, что представление в дополнитель- ном коде не используется): а. 1010 б. 11111 в. 10000 г. 1011110 4. Преобразуйте следующие десятичные числа в восьмерич-
72 Глава 2 ные двоичные числа. Для отрицательных чисел воспользуйтесь представлением в дополнительном коде. а. 47 б. -32 в. 63 г. —100 д. 129 5. Преобразуйте следующие двоичные числа в шестнадцате- ричные (в предположении, что представление в дополнительном коде не используется) : а. 1010101010 б. 11001101010 в. 1010010101001 г. 10101111100 д. 111111110 е. 110111100011 6. Преобразуйте следующие шестнадцатеричные Числа в двоичные: a. 14FB б. 23АА в. 10ВВ г. FF18 7. Преобразуйте следующие десятичные числа в шестнадца- теричные: а. 4512 б. 2489 в. 9431 г. 285 8. Преобразуйте следующие шестнадцатеричные числа в де- сятичные: a. 1FB7 б. 6АС в. C1F3 г. 37AC3 9. Преобразуйте следующие двоичные числа в десятичные при условии, что каждое из чисел задано восемью двоичными разрядами, а отрицательные значения представлены в дополни- тельном двоичном коде: а. 00010111 б. 11101001 в. 11111111 г. 11110000 д. 10101010 е. 01010101 ж. 10000000 з. 10000001 и. 01111111
Глава 3 Введение в архитектуру и язык ассемблера системы VAX В то время как в системе TOYCOM имеется, всего 10 выпол- няемых команд, стандартный вариант вычислительной системы VAX располагает 255 командами. Для этого набора выполняе- мых команд и большого числа невыполняемых директив ассем- блера имеется транслятор языка ассемблера, разработанный фирмой Digital Equipment Corporation (DEC). Объем памяти VAX измеряется не 100 словами фиксированной длины, как у TOYCOM, а миллионами ячеек памяти нескольких размеров. В системе VAX имеется 16 регистров, а не единственный (акку- мулятор), как в TOYCOM. Большинство из них может исполь- зоваться для хранения как значений операндов-источников и операндов-результатов, так и специальной информации для раз- ных способов адресации к исходным данным и результатам. Все это делает освоение языка ассемблера VAX, конечно, более тру- доемким, чем овладение соответствующими средствами програм- мирования TOYCODE. Все системные программы VAX, созданные фирмой DEC, вы- полняются под управлением операционной системы VMS (Vir- tual Memory System — система с виртуальной памятью). В на- бор системных программ входит программа, выполняющая трансляцию с языка ассемблера на язык машинных команд (транслятор языка ассемблера). Все рассматриваемые далее ди- рективы языка ассемблера предназначены для работы с этим транслятором, созданным фирмой DEC. Язык ассемблера системы VAX-11 принято называть Macro VAX-11, чтобы отличать его от Macro —языка ассемблера мини- ЭВМ PDP-11, разработанных той же фирмой DEC. В данной книге применительно к вычислительной системе VAX-11 исполь- зуется термин «язык ассемблера». 3.1. Введение в архитектуру системы VAX Обобщенная структура системы VAX-11/780 показана на рис. 3.1. В более поздних моделях системы, как показано ниже, исполь- зуется другой способ соединения памяти и периферийных уст- ройств. В остальном же рис. 3.1 применим для описания принци-
74 Глава 3 пов организации всех существующих модификаций вычислитель- ной системы VAX. Консоль представляет собой терминал, используемый для на- чальной загрузки системного программного обеспечения, моди- фикации его средств и изменения системных параметров. За- грузка системных программ выполняется посредством подсоеди- ненной к машине недорогой внешней памяти — накопителя на гибких магнитных дисках. Связь центрального процессора VAX с оперативной памятью и внешними устройствами (за исключе- нием консоли) осуществляется через так называемое синхрон- ное межсоединение. Физически оно представляет собой набор гнезд, в которые могут вставляться модули на печатных схемах.
Введение в архитектуру и язык ассемблера системы VAX 73 Таково конструктивное решение взаимосвязи основных функцио* нальных элементов модели VAX-11/780. В моделях более позд* них разработок возможны другие решения. VAX проектировалась как машина, на которую со временем могут перейти пользователи ранней разработки фирмы DEC — машины PDP-11. VAX может быть соединена со всеми внеш- ними устройствами (накопителями на магнитных дисках и лен- те, печатающими устройствами и т. д.) через стандартные интер- фейсы номенклатуры PDP-11. (Физически интерфейс представ- ляет собой упорядоченный набор проводов с разъемами для под- ключения одного или нескольких кабелей. Примером простей- шего интерфейса является обычный трехпроводной кабель элек- тропитания жилых помещений с розеткой для подключения раз- личных приборов.) Внутренняя память VAX представляет собой совокупность элементарных адресуемых ячеек размером 1 байт, Байт состоит из 8 бит. В каждом байте отдельному биту условно присваи- вается свой номер. Биты нумеруются справа налево цифрами от О до 7. Адресацию элементов оперативной памяти можно предста- вить следующим образом: В системе VAX для представления данных любого типа (за ис- ключением одного) используется поле, размер которого равен одному или нескольким байтам. Имеется четыре типа целых чи- сел: размером, байт, слово (два смежных байта), длинное слово
76 Глава 3 (четыре смежных байта) и двойное длинное слово (восемь смеж- ных байтов). В данной главе рассматриваются некоторые команды, выполняющие операции с длинными словами. Целые числа других типов и соответствующие команды рассматривают- ся в гл. 6. Отрицательные целые числа всех типов представляют- ся в дополнительном коде (см. гл. 2). Адресное пространство ЭВМ принято характеризовать диа- пазоном возможных значений адресов ее оперативной памяти. Адресное пространство TOYCOM имеет 100 адресуемых слов па- мяти. В командах TOYCOM предусматривается 2 десятичных разряда для адресации к областям памяти. В противоположность TOYCOM для представления адреса в системе VAX используется длинное слово, т. е. 32 двоичных разряда. Десятичное значение максимального 32-разрядного двоичного числа равно 4 294 967 295. Если к этому огромному числу добавить 1 (в памяти машины используется адрес, рав- ный нулю), то получим размер адресного пространства VAX. Понятие размера адресного пространства имеет в вычисли- тельной технике определенное назначение. В большинстве ЭВМ адресация осуществляется посредством двоичных чисел, поэтому размеры соответствующих адресных пространств обычно пред- ставляются как число 2 в некоторой степени. Единственное ис- ключение составляют вычислительные машины (к ним VAX не относится), в основе которых лежат операции над десятичными числами. Но таких ЭВМ немного. При оценке размеров памяти пользуются особыми сокращениями. Так, 2,0(1024ю) из-за бли- зости к числу 1000 обозначаются буквой К, как сокращение от кило... . Например, 16К байт, или 16 килобайт, или 16 КВ — это размер памяти, равный 16-1024 = 16384 байт. Аналогично, 220(1048576ю) из-за близости к числу 1000000 обозначается бук- вой М, как сокращение от мега... . Например, 16 Мбайт, или 16 мегабайт, или 16 МВ — это 16777216 байт. Наконец, 230( 1073741824ю) из-за близости к числу 1000000000 обозначает- ся буквой G, как сокращение от гига... *>. В соответствии с этим 4G байт, или 4 гигабайт, или 4GB — это 4294967296 байт. Возможно, что изложенное выше не дает ясного представле- ния о различии между размером адресного пространства и дей-i ствительным размером оперативной памяти ЭВМ. Если адрес* ное пространство машины равно 4GB, это еще не значит, что та< ков и объем ее памяти. В действительности объем памяти боль- шинства последних моделей VAX не превышает 8МВ. Типовая конфигурация системы VAX располагает памятью от 2МВ до п «Кило» и «Мега» — компоненты сложных слов, берущие свое происхо- ждение из слов греческого языка khilioi (тысяча) и mega (большой) «Гига» выполняет те же функции для обозначения миллиарда. — Прим, ред.
Введение в архитектуру и язык ассемблера системы У4Л 77 4МВ. К тому же значительная часть этой памяти пользователю не доступна: примерно половина ее занята системными програм- мами (в основном операционной системой VMS). В менее мощных ЭВМ прежних выпусков выход значения ад- реса (принадлежащего адресному пространству) за пределы значений адресов реальной оперативной памяти считается недо- пустимым. Однако во многих больших современных ЭВМ, вклю- чая VAX, применяется особая форма представления запоминаю- щей среды, именуемая «виртуальной памятью». При этом соз- дается полное впечатление, что всем элементам адресного про- странства соответствуют элементы оперативной памяти незави- симо от реальных размеров последней. Само название системы VAX (Virtual Adress extended — «расширенная виртуальными адресами») указывает на то, что данная вычислительная система с виртуальной памятью. Принципы организации виртуальной па- мяти не просты для понимания, однако для изучения языка ас- семблера глубокое понимание организации виртуальной памяти не требуется. Поэтому в данной книге она детально не рассма- тривается. Однако в дальнейшем, говоря об адресах памяти, бу- дем подразумевать адреса виртуальной памяти. В состав центрального процессора (ЦП) VAX входит логиче- ское устройство, управляющее извлечением команд из памяти и их выполнением, а также арифметическое и логическое устрой- ство (АЛУ), реализующее выполнение команд. В состав ЦП входит также ряд регистров. Некоторые из них предоставляются в распоряжение пользователей, а другие предназначены исклю- чительно для работы ЦП. Пользователи могут работать с 16 ре- гистрами ЦП размером 32 двоичных разряда каждый. Двена- дцать из них (R0—R11) являются регистрами общего назначе- ния (ограничения на их применение рассмотрены в гл. 9). Ре- гистры R0—R11 могут использоваться в тех же целях, что и ак- кумулятор в TOYCOM. Кроме того, с их помощью можно фор- мировать адреса операндов (см. гл. 7 и 8). Оставшимися че- тырьмя регистрами VAX могут пользоваться только опытные программисты, понимающие особую роль этих регистров в си- стеме. Здесь приведем только названия этих регистров, их на- значение подробно описывается в последующих главах. Регистр R12 называется указателем параметров (АР), a R13 — указате- лем блока вызова (FP). Эти регистры используются в VAX для организации межпрограммных связей. Регистр R14, именуемый указателем стека (SP), содержит адрес начала (вершины) об- ласти памяти, содержащей данные особой структуры, которую называют стеком. Регистр R15 используется в качестве счетчика команд (PC). Как и в TOYCOM он используется для управле- ния последовательностью выполнения команд. В TOYCOM со- держимое счетчика каждый раз увеличивается на длину коман-
78 Глава 3 ды. В противоположность этому содержимое счетчика команд системы VAX каждый раз получает приращение, равное длине поля операндов данной команды. Например, для команды, имею- щей только один операнд, во время обработки кода операции в счетчике команд находится адрес этого операнда. Когда ЦП приступает к анализу адреса операнда, в счетчике команд нахо- дится уже адрес следующей команды. В состав ЦП VAX входит также регистр из 32 двоичных раз- рядов, называемый длинным словом состояния процессора (PSL). Его старшие 16 двоичных разрядов содержат информа- цию о состоянии процессора. Изменение этой информации разре- шено только привилегированным системным программам и не разрешено программам пользователей. Младшие 16 двоичных разрядов этого регистра образуют так называемое «слово со- стояния программы» (PSW). В этом слове содержится информа- ция о текущем состоянии выполняемой программы. Особенно- сти его использования при передаче управления в программах рассматриваются в гл. 4. 3.2. Команды арифметики целых чисел размером длинное слово В данном разделе рассматривается несколько команд языка ас- семблера для выполнения пересылки и арифметических опера- ций над целыми числами размером длинное слово (4 байта). 3.2.1. Символическая адресация и способы выделения памяти Символические имена в языке ассемблера VAX имеют то же назначение, что и в TOYCODE, однако в системе они исполь- зуются и для многих других целей. Символические имена пред- ставляют собой последовательности, состоящие из букв, десятич- ных цифр и знака подчеркивания ( ). Имя может состоять из 31 символа и должно начинаться с цифры. Допустимо, но не же- лательно использование в имени знаков доллара и точки, по- скольку они применяются в системных программах. Культура программирования требует, чтобы используемые имена имели определенный смысл — были бы содержательными именами обозначаемых полей. Для формирования имен, состоя- щих из нескольких слов, может применяться символ подчеркива- ния. Например, на языке ассемблера допустимы такие имена, как SUM-OF NEGATIVES, MALE-TOTAL или TOTAL-DEBT. (Следует отметить, что хотя в программах на языке ассемблера могут использоваться как строчные, так и прописные буквы, транслятор языка ассемблера их воспринимает как прописные.)
Введение в архитектуру и язык ассемблера системы VAX 79 Подобно командам TOYCODE, команды языка ассемблера системы VAX-11 также разделяются на выполняемые и невыпол- няемые. Первые преобразуются в машинные команды, вторые, именуемые директивами, содержат управляющую информацйю для транслятора языка ассемблера и не преобразуются им Д машинные команды. В определенном смысле директивы языка ассемблера тоже являются выполняемыми: их выполняет транс* лятор языка ассемблера. Они легко отличимы от выполняемых команд, поскольку текст директивы всегда начинается с символа точки (•), а выполняемой команды с буквы. Формат команд языка ассемблера похож на формат команд TOYCODE: сначала размещается метка (она может отсутство- вать), затем — код операции, операнды и комментарий. Как и в TOYCODE, отличить метку от кода операции достаточно про*, сто, поскольку метки должны заканчиваться двоеточием. Ком- ментарии от операндов отделяются точкой с запятой. Итак, фор- мат команды можно представить в следующем виде: [метка:] КОП операнд(ы) [; комментарий] Квадратные скобки указывают, что использование заключенного в них элемента необязательно. Комментарии могут (и по воз- можности должны) размещаться в отдельных строках. Это целе- сообразно, поскольку они, как правило, относятся не к одному, а нескольким операторам. К тому же в строке, занимаемой командой, часто недостаточно места для текста комментария. Метки также могут размещаться (и довольно часто) на отдель- ных строках. В таких случаях адрес метки соответствует адресу следующего байта программы. Текст команды можно продолжать на следующей строке, если данную строку завершить знаком минус (—). Однако за- прещается переносить часть символического имени. Строка про- белов всегда заканчивает продолжение. (Вообще, текст команды редко переносят на следующие строки: в этом практически нет необходимости, да и текст такой команды читать весьма не- удобно.) В языке ассемблера имеются две директивы выделения длин- ных слов для целочисленных данных. Директива «LONG обеспе- чивает выделение по крайней мере одного длинного слова па- мяти и позволяет присвоить содержимому выделяемых областей начальные значения. Формат этой директивы: [метка:] .LONG список-констант Список констант может включать выражения, в результате вычисления которых определяются значения каждой константы. Однако для простоты проводимых здесь рассуждений будем по- лагать, что список констант состоит из разделяемых запятыми
80 Глава 3 десятичных чисел, за каждым из которых в квадратных скобках может указываться коэффициент повторения данного числа. На- пример, директива HEIGHT: .LONG 47 выделяет область памяти размером длинное слово, присваивает этой области символическое имя HEIGHT, а ее содержимому значение 47. Директива LIST: .LONG 36, 24, 36 выделяет память размером три длинных слова, присваивает пер- вому из них символическое имя LIST, а содержимому этих длин- ных слов значения 36, 24 и 36 соответственно. На данном этапе рассуждений будем полагать, что коэффи- циент повторения можно задавать только целым числом, заклю- ченным в квадратные скобки. Так, директива TABLE: .LONG 20 [10], 6, 10(5] выделяет память размером в шестнадцать длинных слов; пер- вым десяти из них присваивает значение 20, одиннадцатому — значение 6 ,а последним пяти — значение 10. Директива .BLKL используется для выделения одного или нескольких длинных слов с присвоением их содержимому исход- ных нулевых значений. Формат этой директивы: [метка:] .BLKL количество-длинных _слов Единственный операнд команды определяет количество резерви- руемых в памяти длинных слов, содержимому которых присваи- ваются нулевые значения. Например, SCORES: .BLKL 5 выделяет 5 длинных слов; первому из них присваивает символи- ческое имя SCORES, а содержимому каждого слова — нулевое значение. В качестве операнда директивы .BLKL допустимо ис- пользование не только целых чисел, но выражений определен- ного вида; они рассматриваются в последующих разделах. Целые числа, для представления которых требуется поле длиной несколько байтов, размещаются в смежных байтах па- мяти в порядке, обратном следованию байтов, представляющих разряды чисел при их записи. Например, шестнадцатеричное число 12345678 располагается в памяти следующим образом; 78 56 34 12
Введение в архитектуру и язык ассемблера системы VAX 81 Хотя такой способ размещения целых чисел в памяти ма- шины кажется несколько необычным, он значительно увеличи- вает гибкость функционирования ЭВМ. Рассмотрим, в частно- сти, регистр или двойное слово памяти, содержащее число, мень- шее Ю010- Подобные числа в ряде случаев удобно использовать как значения операндов размером байт. Благодаря описанному выше размещению целых чисел размером несколько байтов об- ращение к регистру или длинному слову памяти как к байту приводит к выборке первого, младшего байта числа. Благодаря этому адресация оказывается правильной и удобной (значение последнего байта в рассматриваемом случае равно нулю). Если бы байты длинного слова размещались в памяти в естественном порядке их следования при записи числа размером длинное сло- во, то старший байт оказался бы первым, а это не очень удобно для практических приложений. 3.2.2. Форматы простых машинных команд В командах, рассматриваемых в данной главе, применяются две формы задания операндов: посредством символических адресов, определяемых директивами .BLK.L и .LONG, и указанием но- мера регистра (последнее используется в данной главе реже). Рассмотрим, как реализуются эти две формы задания опе- рандов в машинных командах VAX. Для сравнения напомним, что все машинные команды TOYCOM имеют один и тот же про- стой формат: два десятичных разряда для кода операции и столько же для записи адреса операнда. Поскольку VAX — бо- лее сложная машина, естественно ожидать, что в ней много разнообразных форматов машинных команд. Формат любой машинной команды системы VAX имеет сле- дующий обобщенный вид: спецификация _ операнда _п ... спецификация _ операнда _ 2 спецификация _ операнда _/ КОП Первый байт команды представляет код операции (КОП). Для большинства команд VAX для полного представления КОП достаточно одного байта. В систему команд отдельных версий VAX входят команды с двухбайтовым КОП, однако в данной книге они почти не рассматриваются.) В полях спецификация операнда полностью определяются со- ответствующие операнды команды. В формате машинной коман- ды КОП и операнды перечисляются в обратном порядке (справа налево). Это согласуется с принятой в системе VAX формой представления машинных команд как горизонтально располо- женной цепочки байтов, последовательная нумерация которых в пределах каждой команды осуществляется справа налево. Мно- гие операнды команды представляются несколькими байтами,
82 Глава 3 Порядок размещения байтов таких операндов подобен ранее описанному порядку размещения байтов чисел размером двойное слово, т. е. по старшрнству бдйты следуют справ^цалево. Такая обратная запись операндов соответствует их'фактическому раз- мещению в команде. Заметим, однако, что язык ассемблера VAX позволяет описывать структуру каждой команды в «естествен- ном» порядке. Спецификация операндов может выполняться большим чис- лом способов, что соответствует большому разнообразию режи- мов адресации в системе VAX. В командах языка ассемблера, операнды которых находятся в регистрах, прямо указываются имена соответствующих регистров, например R7. В специфика- ции операнда машинной команды, адресующегося к регистру, задается также определенное значение в поле код режима адре- сации. Код режима адресации указывает машине, как использо- вать этот регистр для определения местоположения операнда. В частности, когда операнд находится непосредственно в самом регистре, код режима адресации равен 5. Код режима адресации занимает левый полубайт (четыре двоичных разряда) первого байта поля спецификации операнда, а правый полубайт этого поля определяет номер регистра. Полубайта как раз достаточно для указания конкретного номера одного из 16 регистров VAX. Машинная команда с одним операндом в виде номера регистра имеет формат: 1 а 5 | R КОП где R — номер регистра. Над схематическим изображением полей команды приведены порядковые номера битов. Имеются команды с двумя и тремя операндами, определяе- мыми посредством регистров. Они имеют следующий формат; Вторая рассматриваемая здесь форма адресации связана с использованием в командах языка ассемблера символических
Введение в архитектуру и язык ассемблера системы VAX 83 адресов. При записи команд TOYCODE все операнды представ- лялись символическими адресами. При записи машинной коман- ды системы VAX адрес представляется не всеми своими 32 дво- ичными разрядами, а величиной так называемого относительного адреса, отсчитываемого от текущего значения содержимого счет- чика команд (СК) °. Пусть, например, в поле единственного операнда команды имеется символическое имя SUM — адрес не- которой области памяти. Во время обработки программы поль- зователя транслятор языка ассемблера вычисляет разность меж- ду адресом следующей команды и адресом области памяти SUM. Значение этой разности помещается в формируемую машинную команду вместе с дополнительными байтами информации о том, что для вычисления адреса операнда как суммы некоторой базы и смещения необходимо в качестве базы использовать содержи- мое регистра счетчика команд (R15), а в качестве смещения ука- занную разность. Рассмотрим следующий пример: Адрес (шестнадцатеричное число) Команда 0160 код операции SUM 0164 0180 SUM: .LONG 0 Разность между адресом команды, следующей за первой, и ад- ресом области SUM равна lCiS. Это и есть величина смещения, помещаемая в качестве операнда в машинную команду. Во время выполнения программы величина смещения добав- ляется к содержимому счетчика команд. Поскольку в момент обработки операнда SUM в счетчике команд будет находиться адрес следующей команды, сумма значения этого адреса и сме- щения определит правильное значение адреса операнда. В част- ности, в рассматриваемом примере сумма 1С16 и 164i6 равна 18016, что является действительным адресом области памяти *> В дальнейшем такой режим адресации называется относительным «сме- щением к СК», — Прим, ред,
84 Глава 3 SUM. (Адресация «смещением к СК»; еще раз рассматривается в разд. 3.3.2.) Реальный адрес области памяти, полученный описанным выше способом, называют действительным адресом. Машинная команда, единственный операнд которой использует относитель- ную адресацию «смещением к СК»; имеет следующий формат: • • • 2 1 0 • • • Смещение х>г коп Здесь буква X условно обозначает шестнадцатеричную циф- ру, определяющую длину поля смещения. В частности, при ис- пользовании буквы А длина поля равна 1 байт, С — 2 байта (слово) и Е — 4 байта (длинное слово). Величина смещения представляется в дополнительном двоичном коде. Такая сравнительно сложная форма адресации операндов применяется для экономии памяти. Посредством относительной адресаций «смещением к СК» можно адресоваться к любой об- ласти памяти, отстоящей от данной команды на «расстояние» не более 127 байтов, если размер операнда машинной команды ра- вен 2 байта 1). Если длина поля смещения равна одному слову, то диапазон рассматриваемой относительной адресации областей памяти расширяется от 127 до 32767 байт. В результате, если длина поля смещения при относительной адресации «смещением к СК» равна одному байту, размер соответствующего операнда в команде оказывается на 2 байта короче поля, необходимого для записи полного адреса, а если длина поля смещения равна слову, выигрыш в длине операнда оказывается равным одному байту. Пусть области памяти с адресом 42916 присвоено символиче- ское имя SUM, которое является единственным операндом 4-бай- товой команды, расположенной в памяти по адресу 312i6. Тогда конкретный вариант подобной машинной команды с относитель- ной адресацией «смещением к СК» мог бы иметь следующий вида 3 2 1 О С [ F коп 4> Такой операнд состоит из двух ного поля — Fis — информация о том, сация «смещением к СКн содержимое Прим, перев. однобайтовых полей: содержимое од- что используется относительная ядре- второго поля — величина смещения,—
Введение в архитектуру и язык ассемблера системы VAX 85 В данном случае для хранения величины смещения в машинной команде отведено поле размером одно слово. Значение смещения равно 11316 = 42916 — 31616, где 316 —адрес команды, следую- щей за той, в которой содержится обращение к области SUM. Шестнадцатеричная цифра С во втором байте указывает длину поля смещения. Величина смещения представлена в команде правильно, поскольку его старшие разряды расположены слева. Рассматриваемые в данной главе команды имеют один, два или три операнда. Каждый из них может быть задан либо как номер регистра, либо как относительный адрес, отсчитываемый от некоторой базы — значения содержимого команд. Форматы машинных команд допускают сочетание любых этих двух форм адресации для каждого из своих операндов. 3.2.3. Команды пересылки В машине TOYCOM имеются две команды пересылки данных: одна из них (STO) пересылает данные из регистра в память, другая (LD) — из памяти в регистр. В системе VAX имеется группа регистров, но в отличие от других машин с несколькими регистрами для всех форм пересылки данных между регистром и памятью в VAX используются команды с одним и тем же ко- дом операции. Формат команды языка ассемблера MOVL (ПЕ- РЕСЫЛКА ДЛИННОГО СЛОВА) имеет следующий вид: MOVL операнд-источник, операнд-приемник Любой из операндов этой команды или оба операнда могут пред- ставлять собой символический адрес или номер регистра. (В по- следующих разделах показано, что в качестве операндов допу- стимо и использование выражений, обеспечивающих адресацию к памяти.) Приведем примеры допустимых форм записи коман- ды MOVE: MOVL RO, R5 MOVL R3, SUM MOVL COUNT, RIO MOVL COUNT, SUM В первом примере данные пересылаются из регистра R0 в ре- гистр R5, во втором — из регистра R3 в область памяти SUM, в третьем — содержимое длинного слова области памяти COUNT в регистр R10, в четвертом — содержимое длинного слова обла- сти COUNT в область SUM. Для выполнения этих команд не- обходимо, чтобы области SUM и COUNT были определены либо директивой .BLKL, либо директивой .LONG. Подобно командам
88 Глава 3 LD и STO системы TOYCOM команда MOVL всегда изменяет содержимое операнда-приемника и не влияет на содержимое операнда-источника. 3.2.4. Команды арифметических операций В этом разделе рассматриваются команды VAX для выполнения арифметических операций над целыми числами размером длин- ное слово. Команда CLRL (ОЧИСТКА ДЛИННОГО СЛОВА) не имеет аналогов в наборе команд TOYCOM. По этой команде в указы- ваемую область памяти размером длинное слово помещается число 0. Поскольку действие выполняется над одним полем (ме- стом хранения данных), эта команда имеет всего один операнд, задаваемый в виде символического адреса или номера регистра. Примеры: CLRL R3 CLRL SUM Еще две команды VAX не имеют эквивалентов в наборе команд TOYCOM: INCL (УВЕЛИЧЕНИЕ НА 1 ЗНАЧЕНИЯ ДЛИННОГО СЛОВА) и DECL (УМЕНЬШЕНИЕ НА 1 ЗНА- ЧЕНИЯ ДЛИННОГО СЛОВА). Каждая из этих команд имеет единственный операнд размером длинное слово. Команда INCL увеличивает на 1 содержимое области памяти или регистра, ад- ресуемое своим операндом, а команда DECL уменьшает его на 1, Необходимость в выполнении таких операций возникает часто. Поэтому в системе VAX, как и в большинстве других современ- ных ЭВМ, каждая операция реализуется отдельной командой. Например: INCL R3 DECL COUNT Первая команда увеличивает на 1 содержимое регистра R3, а вторая команда уменьшает на 1 содержимое области памяти COUNT. В командах TOYCOM, выполняющих арифметические опера- ции, один операнд задается в явной форме, а другой не явно. Для выполнения четырех арифметических операций в VAX пре- дусмотрены команды с двумя операндами, задаваемыми явным образом. Каждый из этих операндов может быть именем области памяти или номером регистра. Если в команде два операнда, один из них адресуется одновременно и к одному из участников операции и к результату. В TOYCOM такую двойную роль при выполнении арифметических операций выполняет аккумулятор. Если в команде системы VAX два операнда, то отмеченную выше двойную роль играет второй из них.
Введение в архитектуру и язык ассемблера системы VAX 87 Помимо четырех 2-операндных команд для выполнения ариф- метических операций над длинными словами в VAX имеются че- тыре 3-операндные команды. Два операнда подобной команды — это операнды-источники, а один — операнд-приемник (операнд результата). Во время выполнения команды содержимое обла- стей памяти или регистров, адресуемых операндами-источника- ми, не меняется. Команды сложения длинных слов имеют мнемо- нические имена ADDL2 и ADDL3 соответственно в зависимости от того, является ли команда 2- или 3-операндной. Эти команды имеют следующий формат: ADDL2 операнд _1, операнд _2-приемник ADDL3 операнд_1, операнд_2, операнд-приемник Примеры: ADDL2 VALUE, SUM ADDL3 MALES, FEMALES, PEOPLE ADDL2 R3, TOTAL Первая команда складывает содержимое длинного слова па- мяти с адресом VALUE с содержимым длинного слова с адресом SUM и помещает результат снова в область SUM. При этом уничтожается прежнее содержимое SUM. Вторая команда скла- дывает содержимое длинного слова памяти с адресом MALES с содержимым длинного слова с адресом FEMALES и помещает результат в область памяти PEOPLE. Содержимое областей MALES и FEMALES не меняется, а содержимое области PEOPLE, конечно, будет изменено. В третьем примере содержи- мое регистра R3 складывается с содержимым длинного слова памяти с адресом TOTAL и результат помещается в ту же об- ласть TOTAL, замещая прежнее содержимое этой области. Команды вычитания, умножения и деления похожи на коман- ды сложения. Для вычитания (с двумя и тремя операндами) предусмотрены команды SUBL2 и SUBL3 следующего формата: SUBL2 вычитаемое, уменьшаемое „операнд-приемник SUBL3 вычитаемое, уменьшаемое, операнд-приемник При выполнении 2-операндной команды уменьшаемое уничтожа- ется, поскольку его место занимает результат вычитания. При выполнении 3-операндной команды значения уменьшаемого и вы- читаемого сохраняются неизменными. Например, посредством команды SUBL3 POSITIVES, INTEGERS, NEGATIVES вычисляется значение переменной NEGATIVES, вычитая значе- ние переменной POSITIVES из значения переменной INTEGERS.
88 Глава 3 Команды умножения MULL2 и MULL3 имеют следующий фор- мат: MULL2 множитель, множимое „операнд-приемник MULL3 множитель, множимое, операнд-приемник Обе команды вычисляют произведение множимого, адресуемого вторым операндом команды, и множителя, адресуемого первым операндом. Команда MULL2 помещает результат-произведение на место множимого, команда MULL3 — по адресу, указываемо- му третьим операндом. Команды деления длинных слов DIVL2 и DIVL3 имеют сле- дующий формат: DIVL2 делитель, делимое „операнд-приемник DIVL3 делитель, делимое, операнд-приемник В обоих случаях выполняется деление делимого, адресуемого вторым операндом, на делитель, адресуемый первым операндом. Команда DIVL2 помещает результат-частное на место делимого. При выполнении команды DIVL3 значения делимого и делителя сохраняются, поскольку результат помещается по адресу, ука- зываемому третьим операндом команды. Ни одна из этих команд не обеспечивает получения остатка от деления. 3.2.5. Пример фрагмента программы Выше рассмотрено достаточное число команд для того, чтобы написать небольшой фрагмент программы. (Полную программу составить еще пока невозможно: не определены команды ввода исходных данных в машину и вывода из нее результатов, а так- же неизвестен ряд необходимых директив.) В предлагаемом фрагменте программы вычисляются сумма и среднее арифметическое оценок за три экзамена, сданные уча- щимися. Текст программы начинается с резервирования памяти для всех необходимых переменных, а также для константы 3. Затем выполняется расчет требуемых величин, EXAMI: .BLKL 1 ЕХАМ2: .BLKL 1 ЕХАМЗ: .BLKL 1 SUM: .BLKL 1 AVERAGE: .BLKL 1 THREE: .LONG 3
Введение в архитектуру и язык ассемблера системы VAX 89 ADDL3 EXAMI, ЕХАМ2, SUM ADDL2 ЕХАМЗ, SUM DIVL3 THREE, SUM, AVERAGE Даже этот небольшой фрагмент программы дает представле- ние о значительных возможностях средств языка ассемблера VAX, особенно по сравнению с языком TOYCODE. Отметим, что все данные располагаются в оперативной памяти, хотя для боль- шей эффективности функционирования процессора целесообраз- нее размещать их в свободных, доступных регистрах. Данные размещены в памяти, поскольку регистрам невозможно присваи- вать произвольные символические имена, отражающие «смысло- вое значение» соответствующих переменных, а это затрудняет процесс программирования, снижает его эффективность. Если бы требовалось разработать очень эффективную программу, то можно было бы пожертвовать удобством ее чтения, которое дает введение символических адресов, и воспользоваться регистрами. Однако следует отметить, что если программы невелики, форми- ровать их очень эффективные версии нет необходимости, если же программы большие, то, как правило, можно использовать только весьма органиченное число регистров, поскольку, как это следует из излагаемого в последующих главах, большинство ре- гистров оказывается занятым для выполнения ряда специальных функций. 3.2.6. Использование констант в качестве операндов Существует значительно более простое решение проблемы соз- дания и использования констант, чем предлагаемое в рассмо- тренном выше примере (константа 3). Язык ассемблера систе- мы VAX предлагает два варианта задания операнда команды как константы: в виде так называемого непосредственного опе- ранда и в форме литерала. Выбор того или иного варианта опре- деляет программист или транслятор языка ассемблера. В боль- шинстве случаев программисты предоставляют право такого ре- шения транслятору. Для последнего критерием выбора того или иного решения является минимизация размера поля представле- ния константы. Общая форма 2-операндной команды с одним операндом в качестве константы имеет следующий вид: КОП # константа, операнд_2 Второй операнд редко бывает константой, поскольку он обычно предназначен для размещения результата. Если константа — непосредственный операнд, то команде языка ассемблера
90 Глава 3 MOVL #9999, R3 соответствует машинная команда 6 5 4 3 2 10 5 [з 0 0 0 0 2 7 О »т1 8 [ F D 0 Рассмотрим структуру команды подробно, поскольку это по- может лучше понять машинное представление многих других форм адресации. Прежде всего отметим, что, как это принято в системе VAX, в машинном представлении команды, составляю- щие ее поля (код операции, операнд-1, операнд_2 и т. д.), рас- полагаются справа налево, т. е. в порядке, обратном символиче- ской записи команды на языке ассемблера. Такой, на первый взгляд, непривычный порядок обеспечивает представление кон- станты (270F16) в правильном порядке, как и в случае машин- ного представления смещения для операндов относительной ад- ресации «смещением к СК». Если бы информация в машинной команде записывалась слева направо, значение константы было бы представлено теми же байтами, расположенными в обратном порядке. Второй байт команды является спецификатором опе- ранда. Шестнадцатеричная цифра 8 в левом полубайте означает, что имеет место непосредственный операнд (константа). Шест- надцатеричная цифра F в правом полубайте указывает, что для адресации к этому операнду используется регистр 15(Fie), т. е. счетчик команд. Длина поля представления константы в данном случае равна длинному слову. Такой размер выбран транслято- ром языка ассемблера потому, что в поле КОП заданы операции над длинными словами. Информация в последнем (крайнем сле- ва) байте указывает, что второй операнд команды адресуется к регистру (код режима 5), причем этим регистром является R3. Шестнадцатеричное число в первом по порядку (крайнем спра- ва) байте является машинным представлением кода операции команды MOVL. Представление константы в виде литерала используется при малых числовых значениях констант. Команде MOVL #5, R2 со- ответствует машинная команда 2 10 22. 0 5 D 0 Операнд-литерал занимает один байт (второй) в команде. Литералы можно использовать только для представления целых чисел в диапазоне от 0 до 63. Константы большей величины представляются в виде непосредственного операнда. Команда с представлением константы в форме литерала, предназначенная
Введение в архитектуру и язык ассемблера системы VAX 91 для выполнения операций над длинными словами, на три байта короче аналогичной команды с представлением константы в виде непосредственного операнда. С целью экономии этих трех байтов оперативной памяти транслятор языка ассемблера во всех воз- можных случаях представляет операнд-константу в форме лите- рала. При использовании литерала для представления операнда- константы однобайтовое поле этого операнда содержит нули в шестом и седьмом двоичных разрядах, являющихся указателями представления константы в форме литерала. Остальные шесть разрядов поля операнда содержат константу. В команде на язы- ке ассемблера использование константы в виде непосредственно- го операнда или в форме литерала может быть задано посред- ством соответствующей формы операнда команды (см. гл. 15). На данном этапе изучения языка ассемблера условимся предо- ставлять возможность подобного задания транслятору этого языка. 5.2.7. Команды ввода и вывода Языки ассемблера обычно не содержат специальных средств для операций ввода исходной информации в машину и вывода из нее результатов. В противоположность этому в языках высокого уровня обычно имеются мощные средства для выполнения опе- раций ввода и вывода. Однако даже при выполнении простой операции вывода целого числа из оперативной памяти или ре- гистра на терминал требуется множество трудоемких действий. Сначала число должно быть преобразовано из дополнительного двоичного кода в десятичное число, которое потом должно быть преобразовано в строку символов (обычно в коде ASCII), при- годную для использования терминалом. И наконец, последова- тельность символов в коде ASCII, представляющая значение чис- ла, должна быть передана на терминал. Чтобы не запутаться в этих сложных проблемах, ниже вво- дится некоторое расширение языка ассемблера для выполнения простых операций ввода и вывода. Эти дополнительные команды языка называют макрокомандами. Они представляют собой не- что среднее между обычными командами и операторами языков высокого уровня. Особенности разработки и использования мак- росредств языка ассемблера рассматриваются в гл. И. Одной из макрокоманд является макрокоманда INIT-IO. У нее нет операндов. Она должна быть включена в каждую про- грамму, использующую другие макрокоманды обмена данными с терминалами. Ее назначение — подготовка терминала к работе в режимах ввода и вывода. В программе макрокоманда INIT-IO должна предшествовать другим макрокомандам ввода и вывода,
92 Глава 3 Макрокоманда PRINT.L используется для вывода на терми- нал (дисплей или печатающее устройство) целых чисел разме- ром длинное слово. Она может содержать от одного до 7 пара- метров. Первым параметром должна быть строка символов, ограниченная апострофами. Перед этой строкой должен быть помещен специальный знак «^», назначение которого объясня- ется в последующем изложении. Другие параметры макрокоман- ды, если они присутствуют, могут быть символическими имена- ми, названиями регистров или выражениями. Макрокоманда PRINT L позволяет выводить на терминал строку символов (ли- терал) или строку символов, вслед за которой выводится до 6 числовых значений. Литерал может содержать любой символ, воспроизводимый терминалом, кроме символа «@» и апострофа. Посредством макрокоманды READ.L с клавиатуры термина- ла можно вводить с последующей загрузкой в память целые чис- ла размером длинное слово. О готовности терминала к приему информации с клавиатуры свидетельствует появление вопроси- тельного знака на экране дисплея. Эта макрокоманда позволяет вводить от одного до шести целых чисел в области памяти, ад- ресуемые операндам. Вводимые числа могут отделяться друг от друга запятыми или пробелами. Если количество набранных на клавиатуре чисел меньше количества операндов в макрокоманде, то в незаполненные числами области памяти записываются ну- левые значения. Если количество вводимых чисел превышает ко- личество операндов макрокоманды, то «лишние» числа игнори- руются. Числа, содержащие знак, должны вводиться с указанием этого знака слева от цифры старшего значащего разряда. Макрокоманды PRINT.L и READ.L имеют следующие фор- маты: PRINT.L ^литерал[уарг.1{,арг.2{уарг.3[,арг.4[,арг.5[,арг.6]]\]]\ READ.L арг. 1[,арг.2[,арг.3{, арг.4[, арг.5[,арг.6]]]]] В результате выполнения READ.L и PRINT.L содержимое ре- гистров R0 и R1 изменяется. Примеры использования макрокоманд ввода и вывода содер- жатся в программе, приведенной в разд. 3.3. 3.3. Выполнение программ, написанных на языке ассемблера В предыдущих разделах рассмотрено несколько команд для вы- полнения простых операций над целыми числами размером длинное слово, а также директивы .BLKL и .LONG, посред- ством которых можно выделить память для хранения таких чи- сел. Для формирования программного модуля необходимо еще несколько директив языка ассемблера,
Введение в архитектуру и язык ассемблера системы VAX 93 3.3.1. Директивы .PSECT, .ALIGN, .ENTRY и .AND Директива JPSECT (от Program SECTion — программная сек- ция) имеет многоцелевое назначение. С ее помощью решаются задачи разделения программы, написанной на языке ассемблера, на отдельные части — секции, организации совместного пользо- вания секцией, защиты секции от несанкционированной модифи- кации другими программными модулями. В данной главе рас- сматривается назначение лишь одного из возможных параметров этой директивы. Директива имеет следующий формат: .PSECT имя-программной-секции [,список_параметров] Указание имени программной секции в этой директиве необхо- димо в основном для объединения и совместного использования машинных кодов отдельных фрагментов программы. В частно- сти, если две отдельные секции программы начинаются директи- вами .PSECT с одним и тем же именем программной секции, то транслятор языка ассемблера объединяет их вместе (подсоеди- няет одну к другой). На данном этапе знакомства с языком ас- семблера имя программной секции приходится упоминать только потому, что оно обязательный операнд директивы. Основной же интерес сейчас представляют параметры .PSECT. В данный момент достаточно рассмотреть лишь один пара- метр директивы .PSECT, а именно тот, который определяет ре- жим выравнивания машинных кодов программной секции на ту или иную границу памяти. В частности, посредством ключевого слова WORD можно заставить транслятор языка ассемблера вы- делять для кода команды или данных (в зависимости от того, что расположено первым в программной секции) область памя- ти, значение адреса которой делится без остатка на 2 (кратность двум определяется ключевым словом WORD, т. е. выраженным в байтах размером слова памяти). Этим параметром приходится пользоваться в связи с тем, что секции, содержащие информа- цию буферов обмена данными с файлами и терминалами, в рас- сматриваемом расширении языка ассемблера должны начинать- ся с адреса, кратного 4. Для выравнивания выделяемой области памяти на ту или иную границу используются следующие ключе- вые слова: BYTE (граница байтов); WORD (граница слов, т. е. адресов памяти кратных 2); LONG (граница длинных слов, т. е. адресов кратных 4); QUAD (граница двойных длинных слов, т. е. адресов, кратных 8) и PAGE (граница адресов, кратных 512). По умолчанию подразумевается использование ключевого слова BYTE, но следует заметить, что это не приводит практически ни к каким действиям транслятора, поскольку любая выделяемая область памяти имеет адрес, равный целому числу байтов (крат- ный 1). Если ориентироваться на предложенное расширение
94 Глава 3 языка ассемблера, то в используемые директивы .PSECT сле- дует включать в качестве параметра ключевое слово LONG. Причем это должно быть выполнено до обращения й «услугам» макрокоманды INITLIO. В гл. 14 это требование объясняется. Если бы не требовалось создавать определенные условия для последующего выполнения макрокоманд ввода и вывода, можно было бы директивой .PSECT и вообще не пользоваться. Есть еще один довод в пользу применения выравнивания: в системе VAX программы выполняются быстрее, если области памяти, предоставляемые данным, выравнены на границы, рав- ные размерам этих областей. Применительно к операциям над длинными словами для подобного выравнивания следует вос- пользоваться ключевым словом LONG. Если при этом директива .PSECT непосредственно предшествует области определения дан- ных, то области памяти размером длинное слово располагаются на границе длинных слов памяти. Выравнивание можно задать также с помощью другой директивы — .ALIGN. Однако эта ди- ректива не может обеспечить выравнивания на границу, по зна- чению большую той, которая определена предшествующей ди- рективой .PSECT. Поэтому если в программе .PSECT отсут- ствует, то по умолчанию выполняется выравнивание на границу байтов (ключевое слово BYTE), а указания директивы .ALIGN не воспринимаются. Все программы на языке ассемблера должны содержать ди- рективу .ENTRY, имеющую следующий формат: .ENTRY символическое-имя, О Первым операндом директивы .ENTRY является символиче- ское имя, которому транслятор присваивает значение адреса вы- полняемой команды, следующей за директивой .ENTRY. Выпол- нение машинного кода программы будет начинаться с этого адреса. Используемое в .ENTRY символическое имя не должно использоваться в качестве метки в тексте программы. Второй операнд директивы .ENTRY применяется для организации пра- вильного обращения к подпрограммам. В данной главе рассма- триваются только программы, и поэтому ненулевые значения второго операнда не описываются. Отметим, что трансляцию программы можно выполнить, даже если она не содержит дирек- тиву .ENTRY. Однако последующее выполнение такой програм- мы невозможно из-за отсутствия в ней адреса точки входа. Каждая программа на языке макроассемблера должна окан- чиваться директивой .END. Эта директива является признаком конца программы. Кроме того, в ней еще раз указывается адрес точки передачи управления (адрес команды, с которой должно начинаться выполнение программы). Формат этой директивы: .END [символическое_имя]
Введение в архитектуру и язык ассемблера системы VAX 95 Если в директиве .END символическое имя используется, оно должно совпадать с символическим именем, используемым в ди- рективе .ENTRY. В. ряде случаев это имя рпускают (например, в подпрограммах), но в последующих примерах с ег.о помощью во всех директивах .END указывается адрес точки входа. Помимо перечисленного выше любая программа на языке ассемблера должна содержать команду, определяющую условия завершения выполнения программы и возвращения управления операционной системе. Нормальное завершение программы и пе- редачу управления операционной системе выполняет макро- команда $EXIT_S. Она не имеет параметров. Воспользуемся рассмотренными составляющими программы на языке ассемблера для построения небольшой программы. (Поскольку средства передачи управления внутри программ из- лагаются в следующей главе, данный пример может показаться достаточно простым.) Д Пример 3.1 • Постановка задачи Исходные данные: три целых числа (FIRST, SECOND и THIRD). Искомый результат: а) сумма трех исходных чисел; б) среднее арифметическое исходных чисел; в) FUN1 = 17 • FIRST/SECOND - THIRD г) FUN2 = THIRD • THIRD + SECOND/3 + I • Программа на псевдокоде: Ввод чисел FIRST, SECOND и THIRD Вычисление суммы и среднего арифметического Вычисление FUN1 = 17 • FIRST/SECOND - THIRD Вычисление FUN2 = THIRD • THIRD + SECOND/3 + 1 Вывод значений суммы, среднего арифметического FUN1 и FUN2 Конец программы Пользуясь текстом программы на псевдокоде, можно напи- сать программу на языке ассемблера. • Программа на языке ассемблера: ; ПРОГРАММА, ВЫПОЛНЯЮЩАЯ НЕКОТОРЫЕ ; АРИФМЕТИЧЕСКИЕ ОПЕРАЦИИ НАД ЦЕЛЫМИ ; ЧИСЛАМИ
96 Глава 3 ; ВЫДЕЛЕНИЕ ПАМЯТИ ДЛЯ ПЕРЕМЕННЫХ .PSECT EXAMPLE, LONG FIRST: .BLKL 1 ; ОБЛАСТЬ ПАМЯТИ ; ДЛЯ ПЕРВОГО ЧИСЛА SECOND: .BLKL 1 ; ОБЛАСТЬ ПАМЯТИ ; ДЛЯ ВТОРОГО ЧИСЛА THIRD: .BLKL 1 ; ОБЛАСТЬ ПАМЯТИ ; ДЛЯ ТРЕТЬЕГО ЧИСЛА SUM: .BLKL 1 ; ОБЛАСТЬ ПАМЯТИ ; ДЛЯ СУММЫ ЧИСЕЛ AVERAGE: .BLKL 1 ; ОБЛАСТЬ ПАМЯТИ ; ДЛЯ СРЕДНЕГО ; АРИФМЕТИЧЕСКОГО FUN1: .BLKL 1 ; ОБЛАСТЬ ПАМЯТИ ; ДЛЯ FUN1 FUN2: .BLKL 1 ; ОБЛАСТЬ ПАМЯТИ ; ДЛЯ FUN2 .ENTRY INIT_IO ; ВВОД ЧИСЕЛ EXAMPLE_3_1, 0 READ.L FIRST, SECOND, THIRD ВЫЧИСЛЕНИЕ СУММЫ И СРЕДНЕГО АРИФМЕТИЧЕСКОГО ADDL3 ADDL2 DIVL3 ВЫЧИСЛЕНИЕ FUN1 MULL3 DIVL2 SUBL3 FIRST, SECOND, SUM THIRD, SUM #3, SUM, AVERAGE = 17 * FIRST/SECOND - THIRD # 17, FIRST, R1 SECOND, R1 THIRD, Rl, FUN1 ; ВЫЧИСЛЕНИЕ FUN2 = THIRD*THIRD + SECOND/3+ 1
Введение в архитектуру и язык ассемблера системы VAX 97 MULL3 DIVL3 ADDL3 INCL THIRD, THIRD, R1 #3, SECOND, R2 RI, R2, FUN2 FUN2 ВЫВОД ЗНАЧЕНИЙ СУММЫ (SUM), СРЕДНЕГО АРИФМЕТИЧЕСКОГО (AVERAGE), FUN1 и FUN2 PRINT.L ~’SUM, AVERAGE =’, SUM, AVERAGE PRINT.L ~’FUN1, FUN2=’, FUN1, FUN2 ; КОНЕЦ ПРОГРАММЫ $EXIT_S .END EXAMPLE_3_1 Порядок следования операндов в арифметических командах может сначала показаться несколько непривычным, но привык- нуть к нему нетрудно. В следующем разделе рассматриваются команды операцион- ной системы VMS, необходимые для выполнения программ, ко- торые написаны на языке ассемблера VAX. Такие команды обес- печивают необходимый интерфейс пользователя с операционной системой, хотя программисты не всегда проводят четкую грань между командами операционной системы и языка ассемблера. 3.3.2. Создание исходного текста программы. Трансляция, редактирование и выполнение Создание файла с исходным текстом программы обычно выпол- няется с помощью редактора текста. Для этого пользователю не- обходим доступ к терминалу ЭВМ. Стандартным расширением спецификации файла с исходными текстами программ на языке ассемблера VAX является символическое имя .MAR, Все файлы текстов, хранимых в памяти программ, должны иметь это рас- ширение спецификации. Первым этапом обработки программы, написанной на языке ассемблера, является трансляция, выполняемая по команде опе- рационной системы $MACRO [/ключевые..параметры] имя-файла Выполнение большинства функций транслятора, которые мо- гут быть заданы ключевыми параметрами (использование кото- 4 Зак. 48Э
98 Глава 3 рых не обязательно), можно осуществить посредством директив языка ассемблера, включаемых в исходный текст программы. Эти ключевые параметры описываются в последующих разделах по мере того, как в них возникает необходимость. Посредством этих директив можно устанавливать различные режимы форми- рования перекрестных ссылок, листингов программы, а также различные режимы отладки. Когда трансляция заканчивается успешно, система формирует и сохраняет для последующего ис- пользования объектный модуль, имя которого (как файла, хра- нимого в памяти) имеет следующую форму: имя-файла .OBJ Вторым этапом обработки программы является операция ре- дактирования связей, формирующая полный объектный модуль, который называют иногда образом задачи, пригодным для по- следующего выполнения. В процессе редактирования объектный модуль (представляющий собой текст исходной программы в ма- шинных кодах) объединяется с разными системными модулями или дополнительными программами. В результате создается файл, имя которого имеет следующую форму: имя_файла .EXE Пуск системной программы LINK, именуемой редактором связей, осуществляется посредством команды $LINK имя-файла В этой команде расширение имени файла можно не указы- вать, если предполагается использование файла с расширением •OBJ. При обнаружении ошибки во время редактирования свя- зей (например, использовано неправильное имя программы) вы- ходной файл типа .EXE не формируется. Если же трансляция и редактирование связей прошли без ошибок, то файл образа задачи (типа .EXE) может быть передан на выполнение коман- дой JSRUN имя-файла И в этом случае указание расширения спецификации файла не обязательно: предполагается использование в качестве вход- ного файла с расширением .EXE. Чтобы избежать необходимости всегда вводить с терминала последовательность, состоящую из трех команд — для трансля- ции, редактирования и выполнения программы на языке ассемб- лера, — можно построить специальный командный файл. Этот файл состоит из последовательности требуемых команд. Чтобы командный файл можно было использовать для любой програм- мы на языке ассемблера, в него включается специальная коман-
Введение в архитектуру и язык ассемблера системы VAX 99 да INQUIRE, позволяющая вывести на экран терминала сообще- ние о необходимости ввода имени файла, в котором содержится исходный текст программы на языке ассемблера ’>. При обнаружении ошибки в процессе трансляции или редак- тирования связей естественно прекратить дальнейшее выполне- ние командного файла. В операционной системе VMS предусмо- трена специальная команда ON ERROR, позволяющая обнару- живать ошибки и прекращать дальнейшую обработку. Следую- щий пример демонстрирует применение этой команды в тексте командного файла: g INQUIRE Pl „ВВЕДИТЕ ИМЯ ФАЙЛА" $ MACRO 'Pl' $ ON ERROR THEN EXIT $ LINK 'Pl' $ ON ERROR THEN EXIT ? ASSIGN/USER SYSgCOMMAND SYSgINPUT $ RUN Tl' Если такая последовательность команд создана в файле MAC.COM, ее можно выполнить, набрав на клавиатуре терми- нала (дисплея) команду @МАС. При этом имя командного файла (в данном случае МАС) может быть любым, однако оно должно иметь расширение .СОМ. Команда ASSIGN включена в этот командный файл для того, чтобы связать системный файл входных данных (имеющий по умолчанию имя SYS$INPUT) с терминалом. Любая программа, выполняемая под управлением этого командного файла, прини- мает исходные данные с терминала. Вводимые в систему данные и выводимые из нее можно по разному располагать на тех или иных внешних устройствах. При переходе от использования од- них внешних устройств к другим требуется незначительная мо- дификация командного файла, подобного приведенному выше. В гл. 14 показано, как изменить командный файл, чтобы можно было принимать данные с любого внешнего устройства. Во время отладки и выполнения программ обычно приходится работать с листингами (текстами) программ. Большую часть этой работы можно выполнять непосредственно на экране видео- терминала. Однако часто бывает полезным получить текст про- граммы на бумаге (твердую копию). Обычно оказывается доста- точным просто распечатать файл с текстом исходной программы. Однако для отладки и анализа структуры машинных команд о Ответ программиста (введенное им имя файла) присваивается перемен- кой, которая может использоваться в других командах файла. В приводимом далее примере такой переменной является ₽1, — Прим, перво, 4*
100 Глава 3 VAX в ряде случаев необходимы листинги текстов программ в машинных кодах с адресами команд и данных. Для получения такого листинга в команду MACRO необхо- димо включить ключевой параметр /LIST. Например, если в тексте командного файла имеется строка g MACRO/LIST PGM1 то выполняется трансляция программы, находящейся в файле PGMI.MAR, полученный объектный модуль помещается в файл PGMI.OBJ, а листинг — в файл PGM1.LIS. Файл типа -LIS мо- жет быть выведен либо на печатающее устройство для получе- ния твердой копии, либо на экран видеотерминала. Имеется воз- можность выводить в виде листинга лишь отдельные части про- граммы (например, те части, которые в данный момент форми- руются или модифицируются). Для этого можно пользоваться директивами .SHOW и .NOSHOW, включаемыми в исходный текст программ на языке ассемблера. Директива .NOSHOW от- меняет вывод текста, a .SHOW снова возобновляет вывод. В этих директивах можно задавать некоторые дополнительные парамет- ры (см. гл. 11). Ниже приводится листинг программы приме- ра 3.1. В первых двух строках листинга указано имя программы. По умолчанию принимается имя .MAIN (в гл. 4 показано, как это имя может быть задано программистом). В этих же строках содержится информация о времени выполнения трансляции и формирования файла листинга, а также указано полное имя файла, содержащего текст исходной программы. В первой половине листинга располагается текст исходной программы. Каждая строка имеет свой номер. Слева от номеров строк расположена колонка адресов машинных кодов. Адреса задаются четырехразрядным шестнадцатеричным числом. Моле- но заметить, что при переходе от команды к команде значение адреса увеличивается на величину длины предыдущей команды. Слева от адресов печатаются машинные коды, сгенерированные транслятором языка ассемблера. Этот код представлен также шестнадцатеричными числами, записанными справа налево. Бли- жайший байт слева от адреса всегда является кодом операции. Вслед за ним (справа налево) располагаются значения операн- дов или их адреса, представленные в шестнадцатеричной системе счисления. Отметим, что для директив .BLKL в качестве подобных зна- чений приводятся адреса следующих за ним областей. Это спе- цифическая особенность листинга, которая не должна нас вво- дить в заблуждение, поскольку фактически этим переменным присваиваются нулевые значения. Для директивы .LONG, как и следовало ожидать, также выполняется это правило. Для мно«
Введение в архитектуру и язык ассемблера системы VAX 101 гих директив, а также для макрокоманд ввода и вывода машин- ные коды не приводятся. В то же самое время, как можно заме- тить, некоторые из них занимают достаточно много памяти. При- мером может служить макрокоманда INIT-IO. В данном листинге все относительные адреса, отсчитываемые от счетчика команд (адресация «смещением к СК»), имеют раз- мер поля смещения, равный слову. Разность адресов полей, со- держащих значения переменных, и адресов команд, в которых выполняются обращения к этим переменным, слишком велика для ее представления байтом, но весьма незначительна, чтобы использовать для этих целей длинное слово. Рассмотрим для примера формирование относительного адре- са первого операнда первой команды ADDL3. Этот адрес, зада- ваемый как смещение относительно СК, представлен шестнадца- теричным кодом FD94CF. Напомним, что машинный код запи- сывается побайтно в обратном порядке. Поскольку (в дополне- ние к этому) и само значение смещения, как целое число разме- ром слово, записывается также побайтно в обратном порядке, в листинг оно выводится в правильном порядке!). Содержимое первого байта, равное CF, означает, что используется относи- тельная адресация «смещением к СК», причем длина полей сме- щения равна слову. FD94 — значение смещения, занимающего одно слово памяти. Это отрицательное смещение, абсолютное значение которого можно найти, если его представить в двоич- ной форме и вычислить соответствующий дополнительный код: FD9416=1111 1101 1001 01002. Двоичный дополн. код = 0000 0010 ОНО 1100 Абсолютн. значение = 26С16 Адрес первого операнда (FIRST) рассматриваемой команды равен 0. Теперь легко убедиться в том, что во время вычисления действительного адреса операнда содержимое счетчика команд указывает на поле следующего операнда машинной команды (значение 26Ci6 является адресом байта кода режима адресации в поле представления второго операнда). Приведенный ниже листинг является лишь частью файла, создаваемого по команде MACRO/LIST. Транслятор выводит на печать также большую таблицу символических имен, которая на данном этапе изучения языка ассемблера не представляет осо- бого интереса. В этой таблице символические имена, используе- мые в программе, расположены среди множества символических имен, появляющихся в расширениях макрокоманд ввода/вывода. Конечно, в ряде случаев возникает необходимость отыскать в ° Младшие шестнадцатеричные разряды адреса расположены справа, — Прим, перев.
• Программа на языке ассемблера 21 - NOV — 19В2 12:00:20 VAX-11 Macro V03*00 Page 1 21—NOV— 1982 11:58:27 DRA1: [RSEBESTAJEX31.MAR; 3 0000 1 ; ПРОГРАММА, ВЫПОЛНЯЮЩАЯ НЕКОТОРЫЕ 0000 2 ; АРИФМЕТИЧЕСКИЕ ПРЕОБРАЗОВАНИЯ 0000 3 ; 0000 4 ; ВЫДЕЛЕНИЕ ПАМЯТИ ДЛЯ ПЕРЕМЕННЫХ 0000 5 ; 00000000 6 ,PSECT EXAMPLE, LONG 00000004 oooo 7 FIRST: .BLKL I 00000008 0004 8 SECOND: .BLKL 1 oooooooc 0008 9 THIRD: .BLKL 1 00000000 oooc 10 SUM: .LONG 00000014 0010 11 AVERAGE: .BLKL 1 00000018 0014 12; 0000001C 0014 13 FUN1: .BLKL 1 0000 0018 14 FUN2; .BLKL 1 001C 15 .ENTRY EXAMPLE-3-1. 0 001E 16 INIT-IO 0251 17 0251 18 ; ВВОД ЧИСЕЛ В ОБЛАСТИ 0251 19 ; ПАМЯТИ FIRST, SECOND И THIRD 0251 20 READ-L FIRST, SECOND, THIRD 0268 21 ; 0268 22 ; ВЫЧИСЛЕНИЕ СУММЫ И 0268 23 ; СРЕДНЕГО АРИФМЕТИЧЕСКОГО FD9A CF FD95 CF FD94 CF Cl 0268 24 ADDL3 FIRST, SECOND, SUM
FD93 CF FD92 CF CO 0272 25 ADDL2 THIRD, SUM ?D8F CF FD8E CF 03 C7 0279 0281 0281 0281 26 27 ; 28 ; 29 ; DIVL3 #3, SUM, AVERAGE ВЫЧИСЛЕНИЕ FUN1 = 17* FIRST/SECOND - THIRD 51 FD7A CF 11 C5 0281 30 MULLS # 17, FIRST, R1 51 FD79 CF C6 0287 31 DIVL2 SECOND, R1 FD80 CF 51 FD78 CF C3 028C 0294 0294 0294 32 33 ; 34 ; 35 ; SUBL3 THIRD, Rl, FUN1 ВЫЧИСЛЕНИЕ FUN2 = THIRD * THIRD + SECOND/3 + 1 61 FD6D CF FD70 CF C5 0294 36 MULL3 THIRD, THIRD, Rl 52 FD63 CF 03 C7 029C 37 DIVL3 #3, SECOND, R2 FD70 CF 52 51 Cl 02A2 38 ADDL3 Rl, R2, FUN2 FD6C CF D6 02A8 02AC 02AC 02AC 02AC 02AC 02D9 0304 0304 0304 0304 030D 39 40 ; 41 ; 42 ; 43 ; 44 45 46 ; 47 ; 48 ; 49 50 INCL FUN2 ВЫВОД ЗНАЧЕНИЙ СУММЫ (SUM), СРЕДНЕГО АРИФМЕТИЧЕСКОГО (AVERAGE), FUN1 И FUN2 PRINT-L ’SUM, AVERAGES, SUM, AVERAGE PRINT-L ’FUN1, FUN2=\ FUN1, FUN2 КОНЕЦ ПРОГРАММЫ $EXIT_S .END EXAMPLE_3_1
104 Глава 3 таблице символических имен те из них, которые использованы в программе пользователя, но при этом придется пересматривать всю таблицу целиком. Для приобретения опыта целесообразно по крайней мере один раз отпечатать файл листинга целиком для того, чтобы ознако- миться с его структурой и иметь возможность поупражняться в отыскании символических имен. В то же время при печати текста программы можно отказаться от вывода таблицы симво- лических имен. Можно отказаться от вывода строк после заклю- чительной директивы .END, внеся соответствующие изменения в режим трансляции с помощью редактора текста. Сделаем еще одно и последнее замечание по поводу листин- гов, получаемых при трансляции программы на языке ассембле- ра. Транслятор всегда формирует программу в машинных кодах и ее листинг таким образом, как будто бы начальным адресом программы является 0. Однако в действительности в системе VAX выполнение программ никогда не начинается с адреса 0. Они загружаются в память, начиная с некоторого адреса, боль- шего 200, поскольку первые 200 байт зарезервированы для си- стемных программ. Загрузка программы в память, начиная с ад- реса, отличного от 0, не требует изменения полученных во время трансляции машинных команд, поскольку ее адреса, используе- мые программами VAX, являются относительными. Из-за того, что программа загружается по некоторому адресу, отличному от 0, адреса команд в листинге транслятора будут отличаться от фактических адресов, используемых при выполнении программы (см. в разд. 3.4). 3.4. Ошибки при выполнении программы Одним из главных достоинств листинга, создаваемого трансля- тором в результате обработки исходной программы на языке ас- семблера, является возможность выявления команд, вызываю- щих ошибки на этапе ее выполнения. Эти ошибки являются следствием либо синтаксических ошибок, не обнаруженных во время трансляции, либо логических ошибок в алгоритме решае- мой задачи. Много разных ошибок может приводить к прежде- временному прекращению выполнения программы, однако спо- соб отыскания команды, вызывающей ошибочные действия, оди- наков для них всех. Рассмотрим, как практически происходит поиск ошибки. Для этого в текст программы примера 3.1 введем изменения, приво- дящие к ошибке. В первом операнде первой команды MULL3 удалим знак литерала #. Тогда, в соответствии с синтаксисом языка ассемблера, число 17 в качестве первого операнда коман- ды будет восприниматься не как значение множителя в операции
Введение в архитектуру и язык ассемблера системы VAX 105 умножения, а как адрес местоположения множителя. Поскольку область памяти с адресом 17 предназначена для системного ис- пользования, она защищена от несанкционированного доступа к ней прикладных программ. При попытке программы пользовате- ля обратиться к этой области памяти возникает особая ситуация (access violation — попытка несанкционированного доступа), ре- гистрируемая как ошибка на этапе выполнения. Если пуск такой программы осуществляется с помощью описанного выше команд- ного файла MAC.COM, вычислительная система создает следую- щий листинг: ♦ @МАС PLEASE ENTER FILENAMES ЕХ31 ?4 6 8 ‘ZS'YSTEM-F-ACCVIO t access' violationi reason masK=00i virtual address=0000001i> PC=OOOOODFDt PSL=03C00060 XTRACE-F-TRACEBACK » symbolic stack dump follows Module name routine name line ' «MAIN EXAMPLE reb PC abs PC 00000281 OOOOODFD * Большая часть этой информации не нужна при анализе рас- сматриваемого несложного примера. Отметим те элементы текста листинга, которые помогают отыскать ошибку в данном случае. Прежде всего следует обратить внимание на сообщение, что при выполнении обнаружена ошибка, обусловленная попыткой осу- ществления несанкционированного доступа. Ошибка возникла при выполнении программы с именем .MAIN. (Это имя прини- мается по умолчанию для всех рассматриваемых программ. В следующих главах показано, как можно присваивать имена программным модулям. Имя программной секции, в которой об- наружена ошибка, EXAMPLE. В исходной программе на языке ассемблера это имя определено директивой .PSECT.) Ошибка обнаружена во время попытки доступа к полю с виртуальным адресом 1116= 17ю. Десятичное значение этого адреса совпа- дает с числом, стоящим на месте первого операнда команды MULL3 (не следует забывать, что знак =#= был удален). Содер- жащаяся в тексте листинга запись «ге1 РС» — это условное обо- значение содержимого счетчика команд (281), являющегося от- носительным (отсчет от начала программы) адресом команды, в которой обнаружена ошибка. Эта информация наиболее важна при анализе. Значение «abs РС» (абсолютного значения счетчи-
106 Глава 3 ка команд) и значение PC, приведенное во второй строке инфор- мации об ошибках, равны одной и той же величине DFD. Это значение является действительным адресом команды, в которой обнаружена ошибка. Но поскольку в листинге, создаваемом транслятором языка ассемблера, приводятся только относитель- ные адреса, информация об абсолютном значении счетчика ко- манд является избыточной. Наконец, если теперь снова обра- титься к листингу программы, то можно обнаружить, что адрес 28116 имеет команда MULL3. Она и содержит ошибку. 3.5. Трансляция программы В принципе машинный код программы может быть получен при так называемой однопроходной трансляции (однократном после- довательном чтении и обработке команд исходного текста). Ис- ходная программа представляется транслятору в виде единой последовательности символов, читаемой и обрабатываемой слева направо. Многие строки исходного текста программы на языке ассемблера предполагают выделение памяти во время трансля- ции. Например, директива .BLKL требует резервирования по меньшей мере четырех байтов памяти. Все выполняемые команды языка ассемблера требуют выде- ления достаточного объема памяти для последующего размеще- ния соответствующих машинных команд. Транслятор осуществ- ляет выделение памяти посредством специального указателя (указателя адреса) или адресной переменной, хранящей адрес очередного свободного поля в той области адресного простран- ства, в которой выполняется построение машинных кодов про- граммы. Хотя результат трансляции — программа в машинных кодах — записывается в виде файла на диск, создается она так (с соответствующим назначением адресов команд и меток), как если бы загружалась непосредственно в память. Указатель адреса обычно называют счетчиком адреса (СА). По мере обработки транслятором каждой очередной команды или операнда языка ассемблера значение счетчика адреса увели- чивается на длину этой команды или операнда, последовательно «проходя» все относительные значения адресов пространства памяти, которое представляется для размещения машинных ко- дов программы. Значение СА также используется для расчета смещений при использовании относительной адресации «смеще- нием к СК». Иногда, хотя и весьма редко, оказывается целесо- образным использовать значение СК в командах языка ассемб- лера, указав в соответствующем поле операнда символ точки (.). Такое применение СК описано в гл. 6. Одной из основных задач каждого транслятора языка ассемб- лера является построение таблицы символических имен, В эту
Введение в архитектуру и язык ассемблера системы VAX 107 таблицу включаются все используемые в программе символиче- ские имена вместе со своими адресами. Поскольку программы транслируются так, как если бы для выполнения их необходимо загружать в память, начиная с адреса 0, адреса в таблице сим- волических имен являются, по существу, значениями смещений соответствующих полей от начала программы. Существует строгое соответствие между значениями СА во время трансляции программы и значениями СК во время ее вы- полнения. Поэтому адреса таблицы символических имен, соот- ветствующие символическим именам в программе, являются теми же самыми, которые приводятся в листинге трансляции данной программы. Так, в таблице символических имен приме- ра 3.1 адрес для FUN2 равен 18i6, а адрес для FIRST — 0. Транслятор легко определяет значения адресов меток для включения их в таблицу символических имен, поскольку в мо- мент обработки поля с данной меткой в СК находится требуемое значение адреса. Несколько сложнее определить значение адре- са меток, если операндами команд являются символические име- на, которые определяются в программе после того как исполь- зуются. Так, в частности, почти повсеместно обстоит дело с про- граммами на языке TOYCODE, поскольку область данных рас- полагается за областью команд. Рассмотрим следующий фрагмент программы; LD COUNT COUNT: DC 0 Предположим, что трансляцию выполняет однопроходный транс- лятор. Для обработки команды LD ему необходимо знать адрес, соответствующий символическому имени COUNT. Если это имя не встречалось в предшествующих командах, оно еще не попало и в таблицу символических имен. В таком случае транслятору надлежит его туда поместить и в соответствующем поле адреса таблицы отметить, что этот адрес еще не определен. Обработка команды LD транслятором в принципе должна закончиться по- строением машинного кода данной команды. Однако это не мо- жет быть выполнено, пока транслятор не найдет и не обрабо- тает директиву с символическим именем COUNT. Из-за указанной трудности обработки транслятором ссылок на еще не определенные символические имена, а также по ряду других причин большинство трансляторов языков ассемблера выполняют двухкратный просмотр исходных программ. В тех
108 Глава 3 системах, где файлы с исходными текстами (программами на языке ассемблера) находятся на устройствах прямого доступа, во время трансляции файл с текстом считывается для обработки дважды. В системах с вводом с перфокарт текст с введенной колоды сразу записывается в файл на диске. Для второго про- хода транслятора считывание исходного текста осуществляется с этого диска. Ниже описаны основные действия двухпроходного трансля- тора. Некоторые из них состоят из ряда более мелких операций, однако приводимое описание позволяет составить представление о процессе в целом. Первый проход Присвои.ть нулевые значения счетчику адреса (СА) и ука- зателю длины таблицы символических имен FOR (Для) каждой команды программы на языке ассем- блера DO IF (Если) команда имеет метку THEN (То) поместить имя метки в таблицу символических имен. В качестве адреса записать в таблицу зна- чение СА. IF (Если) символическое имя уже имеется в таблице THEN (То) выдать сообщение об ошибке: «многократно определенное имя» ENDIF (Конец оператора «Если») ENDIF (Конец оператора «Если») Увеличить содержимое СА на длину поля КОП END-FOR (Конец оператора «Для») FOR (Для) каждого операнда DO Вычислить длину операнда Увеличить содержимое СА на длину операнда END-FOR (Конец оператора «Для») Второй проход Присвоить нулевое значение счетчику адреса (СА) FOR (Для) каждой команды программы на языке ассем- блера DO
Введение в архитектуру и язык ассемблера системы VAX 109 Определить КОП машинной команды для КОП команды на языке ассемблера и поместить его в программу на машинном языке Увеличить содержимое СА на длину поля КОП FOR (Для) каждого операнда DO Сформулировать машинный код операнда и поместить его в программу на машин- ном языке Увеличить содержимое СА на длину опе- ранда END-FOR (Конец цикла «Для») IF (Если) требуется файл листинга THEN (То) преобразовать машинные коды команды в символы, пригодные для вывода на печать Записать преобразованные машинные коды команды вместе с текстом этой команды на языке ассемблера в файл листинга ENDIF (Конец оператора «Если») END-FOR (Конец оператора «Для») Выводы 1. В данной главе совершен переход от вопросов программи- рования TOYCOM к наиболее простым элементам языка ассемб- лера системы VAX. 2. Размер адресного пространства VAX равен 4 гигабайт. По- ловина его предоставлена в распоряжение пользователей, поло- вина занята системой. 3. VAX имеет 16 регистров по 32 двоичных разряда каждый. 12 регистров являютсй регистрами общего назначения. 4. Символические имена, которые может вводить програм- мист, могут содержать до 31 символа (буквы, цифры, знак под- черкивания). Символические имена не могут начинаться с цифры. 5. Директива .BLKL выделяет одно или несколько длинных слов памяти и присваивает их содержимому нулевые значения. 6. Директива .LONG выделяет одно или несколько длинных слов памяти и присваивает их содержимому заданные значения. 7. Двумя основными формами адресации является регистро- вая и относительная «смещением к СК». Последняя определяет действительный адрес операнда как сумму адреса данной коман- ды и величины смещения,
ItO Глава 3 8. Команда MOVL пересылает данные размером длинное сло- во. Источником и приемником информации могут быть как ре- гистры, так и области памяти. 9. Команды языка ассемблера, предназначенные для выпол- нения основных четырех арифметических операций, могут иметь два или три операнда. Двухоперандные команды используют второй операнд и как источник данных, и как приемник резуль- тата. Любой операнд команды (операнд-источник, операнд-при- емник) может адресоваться к регистру или области памяти. 10. Имеются три дополнительные арифметические команды: INCL (УВЕЛИЧЕНИЕ НА 1 СОДЕРЖИМОГО ДЛИННОГО СЛОВА, АДРЕСУЕМОГО ОПЕРАНДОМ), DECL (УМЕНЬШЕ- НИЕ НА 1 СОДЕРЖИМОГО ДЛИННОГО СЛОВА, АДРЕ- СУЕМОГО ОПЕРАНДОМ) и CLRL (ОЧИСТКА ДЛИННОГО СЛОВА, АДРЕСУЕМОГО ОПЕРАНДОМ). 11. Константы могут записываться непосредственно на месте операндов команды. Им обязательно должен предшествовать знак #. В машинной команде константа записывается либо не- посредственно, либо в форме литерала. Операнд, определяющий константу, всегда является операндом-источником. 12. Ввод и вывод данных размером длинное слово выполня- ется посредством макрокоманд INIT_IO, READ_L и PRINT_L 13. В программы на языке ассемблера должны включаться директивы .ENTRY и .END. Правильное завершение программы с передачей управления системной программе требует наличия в программе макрокоманды $EXIT_S. Для обеспечения работы системных программ, вызываемых макрокомандами ввода-выво- да, требуется директива .PSECT с ключевым параметром LONG. 14. Пуск программы можно осуществить, выполняя три по- следовательных этапа с помощью команд операционной системы MACRO (для трансляции программы), LINK (для построения «образа» задачи, который может быть передан на выполнение) и RUN (для непосредственного выполнения программы). 15. Во время трансляции может быть получен листинг, содер- жащий обширную информацию об обрабатываемой программе. 16. Хотя трансляция может быть выполнена и за один про- смотр («проход») исходного текста программы, обычно трансля- тор языка ассемблера выполняет два просмотра. Во время транс- ляции формируется важная системная таблица — таблица сим- волических имен. 17. Если во время выполнения программы обнаружена ошиб- ка, то адрес команды, при выполнении которой наличие ошибки фиксируется, можно выявить, читая сообщение об ошибке в ли- стинге трансляции.
Введение в архитектуру и язык ассемблера системы VAX 41 Новые команды ADDL2 DECL INCL MULL2 SUBL2 ADDL3 DIVL2 MOVL MULL3 SUBL3 CLRL DIVL3 Новые директивы .BLKL .END .ENTRY .LONG .PSECT Макрокоманды ввода-вывода и возврата управления $EXIT_S INIT.IO PRINT.L READ.L Новые термины Адресное пространство Арифметическо-логическое устройство Гигабайт Двухпроходной транслятор Действительный адрес Длинное слово состояния процессора (PSL) Интерфейс Килобайт Код режима адресации Мегабайт Операнд-литер ал Относительная адресация «смещение к СК» Ошибка на этапе выполнения Редактирование связей Слово состояния программы {PSW) Смещение Счетчик адреса (СА) Таблица символических имен Шина Вопросы и упражнения 1. Дайте определение адресному пространству. 2. Как называются регистры R12 — R15? 3. Какая половина длинного слова состояния процессора яв- ляется словом состояния программы? 4. Чем следует руководствоваться при формировании симво- лических имен в программе? 5. В чем различие директив .LONG и .BLKL? 6. Почему информация в длинных словах памяти записы- вается побайтно в обратном порядке?
112 Г лава 3 7. Как происходит относительная адресация «смещением н СК»? 8. Перечислите операнды команды DIVL3. 9. В чем различие между представлением константы непо- средственно и в форме литерала, если константа используется как операнд команды? 10. Что выполняется при первом проходе двухпроходного транслятора? 11. Пусть в программе определены три переменные: адрес (шестнадца- теричный) 254 COUNT: .LONG 0 258 VALUE: .LONG 1 25C SUM: .BLKL 1 Преобразуйте следующие две команды в машинный код: адрес 454 MOVL R3, VALUE 459 ADDL3 COUNT, R5, SUM В шестнадцатеричном представлении кодами операций машин- ных команд являются D0 и С1 соответственно. 12. Выполните задание п. И в предположении, что адресами команд являются 268 и 26С соответственно. 13. Выполните задание п. 11 в предположении, что адресами команд являются 20F1D и 20F24 соответственно. Для следующих задач составьте программы на языке ассембле- ра и выполните их отладку. Считайте, что все переменные в п. 14, 15 и 17 располагаются в памяти ЭВМ. 14. Исходные данные: два целых числа. Искомый результат: сумма, разность, частное и произведение этих чисел. 15. Исходные данные: четыре целых числа (FIRST, SECOND, THIRD и FOURTH). Искомый результат: а) сумма четырех чисел б) FUN 1 = FIRST • SECOND - (THIRD/FOURTH) в) FUN2 = (FIRST- FIRST - 1)/(SECOND - 17) 16. Выполните упражнение n. 15 в предположении, что все данные загружены в регистры. 17. Исходные данные: два целых числа (FIRST и SECOND), Искомый результат: a) (FIRST/SECOND)3 б) FIRST4/SECOND2 в) FIRST5/SECOND3
Введение в архитектуру и язык ассемблера системы VAX 113 Примечание. Предполагается, что значения FIRST и SECOND достаточно малы и, следовательно, результат не может оказаться слишком большим числом. 18. Выполните упражнение п. 17 в предположении, что все данные загружены в регистры. 19. Исходные данные: три целых числа (VO, ACCEL и TIME). Искомый результат: величина расстояния, пройденного объ- ектом за время TIME (с), равноускоренно движущимся с началь- ной скоростью V0 (м/с) и ускорением ACCEL (М/с2). При рас- чете воспользуйтесь формулой Расстояние = V0 • TIME + (ACCEL • (TIME2)/2) 20. Исходные данные: три целых числа (LENGTH, WIDTH и HEIGHT). Пусть LENGTH —длина коробки, WIDTH —ее ши- рина, a HEIGHT — высота. Искомый результат: величина полной площади поверхности коробки. 21. Исходные данные: пять целых чисел (COEF1, COEF2, COEF3, COEF4 и X). Искомый результат: значение полинома COEF1 + (COEF2 X) + (COEF3 . (X2)) + (COEF4 • (X3)) Примечание. Желательно оптимизировать структуру программы (минимизируя число выполняемых арифметических операций и пользуясь регистрами во всех возможных случаях). 22. Исходные данные: три пары целых чисел (XI, Y1), (Х2, Y2) и (ХЗ, Y3). Числа каждой пары представляют собой горизонтальную и вертикальную координаты некоторой точки. Искомый результат: площадь треугольника, образованного этими тремя точками, вычисляемая по формуле AREA = ((XI • Y2) - (Х2 • Yl) + (Х2 • Y3) - (ХЗ • Y2) 4- + (ХЗ- Yl) — (XI • Y3))/2
Глава 4 Программирование ветвящихся и циклических вычислительных процессов на языке ассемблера Мощным средством цифровых вычислительных машин является их способность выбирать направление хода вычислений (пере- ходить к выполнению той или иной команды или группы команд из числа возможных альтернативных решений) в процессе вы- полнения программы. Именно эта способность обусловливает возможность формирования из команд циклов. Как уже отмечалось в гл. 1, алгоритм решения любой задачи может быть составлен посредством трех основных алгоритмиче- ских структур: следований, ветвлений (выбора направления хода вычислений) и циклов. Последние предполагают наличие в них проверки условия продолжения (или окончания) циклического повторения операций тела цикла. Программа в примере 3.1, в частности, построена с использованием последовательной пере- дачи управления от оператора к оператору в порядке их следо- вания в тексте программы. Типичными примерами операторов выбора направления хода вычислений являются операторы IF языков Паскаль и ПЛ1, а примерами операторов цикла могут служить операторы WHILE языков Алгол или Паскаль. Освоение правил программирования средствами языка ас- семблера ветвящихся и циклических вычислительных процессов позволит записывать на этом языке разнообразные и удобные для чтения программы. В данной главе рассматриваются воз- можности описания на языке ассемблера VAX указанных алго- ритмических структур. Рассматриваются также команды для определения и сравнения содержимого регистров и областей па- мяти. Они нужны для организации так называемой условной передачи управления и циклов, управляемых счетчиком. 4.1. Команды условной и безусловной передачи управления В вычислительной машине TOYCOM условная передача управ- ления предполагает проверку содержимого аккумулятора (ре- гистра АК) на равенство нулю и на превышение нулевого значе- ния. Хотя возможности машины, содержащей только один ре- гистр общего назначения, весьма ограниченны, указанная про- верка реализуема. Что касается системы VAX, то она распола-
Программирование ветвящихся и циклических процессов Н5 гает 16 подобными регистрами. Вместо того, чтобы с целью упо- мянутой проверки использовать отдельную команду для каждого регистра, предлагается включение в состав команды второго опе- ранда, указывающего местоположение проверяемого значения. Альтернативным решением является использование таких ко- манд арифметических операций, пересылки и некоторых других действий, которые всегда присваивают содержимому некоторых специальных индикаторов определенные значения в зависимости от результата выполнения соответствующих операций !). Эти ин- дикаторы размещаются в одной области, доступной для анализа ее содержимого. Тогда команды передачи управления могут просто проверять отдельные биты этих индикаторов и выполнять или не выполнять соответствующую передачу управления. По- следняя реализуется в системе VAX так же, как и в TOYCOM: посредством изменения содержимого регистра, в котором нахо- дится адрес следующей выполняемой команды. В обеих вычис- лительных системах этот регистр называется счетчиком команд (СК). В машинных командах VAX к содержимому СК обра- щаются по номеру этого регистра, равному F (шестнадцатерич- ная цифра). В гл. 3 отмечается, что слово состояния программы (PSW) является правой половиной длинного слова состояния процессо- ра (PSL). Частью содержимого PSW являются биты — индика- торы состояния. Значения этих битов используются для передачи управления по условию. Установить индикатор означает при- своить значение 1 его соответствующему биту; сбросить, или очистить, индикатор — присвоить соответствующему биту значе- ние 0. Бит 0 (именуемый битом С) PSW является индикатором пе- реноса * 2). Он используется системными программами для пере- дачи управления при выполнении арифметических действий над числами, представляемыми несколькими словами памяти. Бит 1 (бит V) PSW является индикатором переполнения. Он исполь- зуется для индикации того, что результат выполнения операции не может быть корректно представлен в выделенной области памяти. Бит 2 (бит Z) является индикатором нулевого значения. Еди- ничное значение этого бита (индикатор Z установлен) показы- вает, что результат выполнения последней команды равен нулю. Бит 3 (бит N) является индикатором отрицательного значения. о Каждый индикатор предназначен для хранения одного бита информа- ции. Совокупность информации, содержащейся в этих индикаторах, принято называть признаком результата, а представляющие эту информацию биты-ин- дикаторы — битами признака результата. — Прим. ред. 2) 16 двоичных разрядов (битов) слова состояния программы (PSW) про- нумерованы справа налево следующим образом: 0, 1, 2, .15,Прим, ред.
116 Глава 4 Он равен единице, если результат выполнения команды отрица- тельное число. Биты 5, 6 и 7 — биты фиксации ошибки. Каждый из них мо- жет быть установлен (биту присвоено значение 1) для обнару- жения ошибки определенного типа. Если такая ошибка встре- тится во время выполнения программы, то дальнейшее выполне- ние команд будет прервано. Если же соответствующий бит не установлен (ему присвоено значение 0), то появление ошибки данного типа игнорируется. Содержание предыдущих глав позволяет детально описать назначение только одного из битов фиксации ошибки — бита 6. Он используется для регистрации переполнения при выполнении операций с целыми числами. Если этот индикатор установлен (биту 6 присвоено значение 1), то переполнение при операции над целыми числами вызывает прекращение выполнения про- граммы. В гл. 5 объясняется, как устанавливать и сбрасывать индикаторы фиксации ошибок, а в гл. 6 рассматриваются причи- ны появления переполнений. Команды условной передачи управления используют (инди- видуально или парами) значения первых четырех битов (С, V, Z и N). В данной главе рассматриваются следующие разновидно- сти команд условной передачи управления: Символическое обозначение кода операции команды Описание назначения Значения битов- индикаторов BEQL ПЕРЕХОД, ЕСЛИ РАВНО Z = 1 BNEQ ПЕРЕХОД, ЕСЛИ НЕ РАВНО z=o BGTR ПЕРЕХОД, ЕСЛИ БОЛЬШЕ N = 0 и z = о BLSS ПЕРЕХОД, ЕСЛИ МЕНЬШЕ N = 1 BGEQ ПЕРЕХОД, ЕСЛИ БОЛЬШЕ ИЛИ РАВНО N = 0 BLEQ ПЕРЕХОД, ЕСЛИ МЕНЬШЕ ИЛИ РАВНО N=1 или Z = 1 Может показаться, что символические обозначения кода опе- рации команд и их назначения плохо связаны с проверяемыми условиями. Например, одна из команд называется ПЕРЕХО- ДОМ, ЕСЛИ РАВНО, а проверяется в ней условие равенства
Программирование ветвящихся и циклических процессов 117 нулю результата последней выполненной операции. Это несоот- ветствие только кажущееся, что становится ясным после озна- комления с правилами установки и сброса битов-индикаторов. Все команды арифметических операций и команды пересыл- ки, рассмотренные в гл. 3, завершаются установлением в соот- ветствующее состояние битов-индикаторов N и Z. Рассмотрим в качестве примера последовательность команд: MOVL #3, R2 SUBL2 #3, R2 BEQL LOOP Условие, при котором команда BEQL передает управление (команде с меткой LOOP), выполняется, поскольку в результате выполнения команды SUBL2 бит Z становится равным 1. Из названия команд условного перехода следует, что они предполагают сравнение значений двух операндов. Что же ка- сается команд арифметических операций, то выполнение опера- ций сравнения не является их прямой функцией. Некоторая раз- новидность операции сравнения выполняется командой вычита- ния (наряду с формированием результата, который подлежит размещению в заранее известном месте). Однако действия пред- писываемые командами вычитания и условной передачи управ- ления, в определенном смысле противоречат друг другу. Так, со- гласно командам SUBL2 А, В BGTR OUT управление передается по адресу (метке) OUT, если В > А, а не А < В, что можно было предположить, исходя из наимено- вания команды BGTR. Причиной возникновения этой проблемы является запись операндов в команды вычитания в порядке, об- ратном привычному нам. В самом деле, согласно команде SUBL2 А, В вычисляется В — А. Во избежание подобных за- труднений рекомендуется для выполнения сравнения использо- вать специальную команду сравнения целых чисел размером длинное слово каждое (CMPL), имеющую следующий формат: CMPL операнд-источник. 1, операнд-источник_2 По этой команде выполняется вычитание значения второго операнда из значения первого операнда и в зависимости от по- лучающегося результата устанавливаются биты-индикаторы N, Z или С. Фактический же результат сравнения никуда не запи- сывается и значение ни одного из операндов не изменяется. В данном случае вычитание выполняется привычным для нас (со времен обучения в школе) образом, а не так, как описано
118 Глава 4 в гл. 3 (применительно к командам SUBL2 и SUBL3). Конечно, разработчики VAX не стремились только сделать все привычным для пользователя ЭВМ: есть целый ряд доводов в пользу приме- нения различного порядка записи операндов в командах. В фор- матах всех команд операнды-источники (исходные данные) за- писываются в левой части списка операндов, а операнды-приемни- ки (результаты)—в правой. Поэтому первым операндом коман- ды вычитания является вычитаемое !). Но в команде CMPL оба операнда являются операндами-источниками, поэтому целесооб- разно их размещать в привычном (общепринятом) порядке. Иногда оказывается полезным управлять значениями битов N и Z в зависимости от значения содержимого длинного слова. Это можно выполнить с помощью команды TSTL (TeST Long- word— ПРОВЕРКА ДЛИННОГО ОЛОВА), имеющей следую- щий формат: TSTL операнд-источник Эта команда «очищает» индикаторы V и С (присваивает этим битам нулевые значения) и воздействует на индикаторы N и Z в зависимости от значения содержимого длинного слова, адре- суемого ее единственным операндом. Если это содержимое мень- ше нуля, то индикатор N устанавливается, а индикатор Z сбра- сывается; если же оно равно нулю, то Z устанавливается, a N сбрасывается. Действие команды TSTL подобно действию коман- ды CMPL, у которой второй операнд равен нулю. Однако коман- да TSTL короче, компактнее по форме представления. Анализи- руя содержимое длинного слова, данная команда является пред- варительной операцией к условной передаче управления в зави- симости от значения этого содержимого подобно тому, как за- грузка числа в аккумуляторе TOYCOM — подготовительная опе- рация к условной передаче управления в этой гипотетической ЭВМ. Рассмотрим еще одну команду языка ассемблера системы VAX — команду безусловной передачи управления. Ее аналогом в языке TOYCODE является команда с символическим именем кода операции В. В VAX имеются три разновидности команд безусловной передачи управления. Машинные коды этих команд имеют разную длину. Рассмотрим здесь только две, более про- стые формы этой команды, имеющие следующий обобщенный формат: BRx адрес_передачи _у правления В каждом конкретном случае код операции имеет символиче- ское имя BRB или BRW. В обих случаях адрес, по которому 4) В двухоперандной команде вычитания второй операнд — уменьшае- мое — является и источником исходных данных и результатом (на его месте размещается разность). — Прим. ред.
Программирование ветвящихся а циклических процессов 119 передается управление, определяется смещением относительно содержимого счетчика команд (СК). В машинном формате команды, имеющей код операции BRB, для хранения смещения предусмотрено поле размером байт. Это позволяет в качестве адреса передачи управления указывать поле, отстоящее от данной команды не более чем на 127 байт. Это существенное ограничение и потому пользоваться данной командой целесообразно только в случаях острого дефицита па- мяти. Более того, в момент написания программы адрес пере- дачи управления может отличаться от текущего адреса не более чем на 127 байт, однако дальнейшие изменения программы (до- бавление новых команд) могут привести к выходу за этот пре- дел и как следствие — к ошибке при выполнении команды BRB. В машинном формате команды BRW для представления сме- щения адреса передачи управления относительно содержимого СК используется поле размером слово (2 байта). Это позволяет адресоваться к полям, отстоящим от поля текущего адреса (на- ходящегося в СК) на «расстоянии» до 32767 байт, что, по суще- ству, достаточно для большинства программ. Форматы обеих команд — BRB и BRW — не содержат байта с кодом режима адресации. Поэтому их машинные коды очень короткие: длина команды BRB равна двум байтам, а команды BRW — трем. Машинные команды условного перехода имеют длину всего в два байта: один байт для кода операции, а другой для смеще- ния. Адрес, по которому передается управление, получается сло- жением смещения с обновленным содержимым счетчика команд. К моменту выполнения этой операции сложения содержимое счетчика команд равно адресу не текущей, а очередной команды. Это справедливо и для вычисления адреса команд BRB и BRW. Хотя формат команды условной передачи управления и компак- тен, он является причиной определенных затруднений при про- граммировании. Поскольку для хранения смещения представля- ется только один байт, адрес, по которому передается управле- ние, не должен отличаться более чем на 127 байт от адреса кон- ца данной команды и на 126 байт от адреса ее начала. Иногда требуется адресация за пределы этого диапазона. В таких слу- чаях рекомендуется использовать условную передачу управления при выполнения обратного условия с целью обхода команды BRW. Так, если при установленном индикаторе Z требуется пе- редавать управление по адресу (метке) LOOP, то приемлемо следующее решение: BNEQ AROUND BRW LOOP AROUND:
120 Глава 4 4.2. Циклы с предварительной проверкой условия В гл. 1 рассмотрена стандартная методика перехода от пред- ставления на псевдокоде цикла с предварительной проверкой ус- ловия к программе на языке TOYCODE. Ниже рассматривается аналогичное преобразование для представления подобных цик- лов на языке ассемблера системы VAX. Поскольку язык ассем- блера обладает значительно большими возможностями по срав- нению с языком TOYCODE, подобная задача в данном случае решается значительно проще. Общее правило преобразования написанного на псевдокоде цикла с предварительной проверкой условия во фрагмент программы на языке ассемблера может быть представлено в следующей форме: Текст на псевдокоде WHILE условие DO END-DO Текст на языке ассемблера LOOP: Команда для вычисления выраже- ний, образующих условие Переход на метку LOOPEND, если условие не выполняется Переход на метку LOOP по коман- де BRW LOOPEND: Ниже приведены два примера описания циклов на псевдо- коде с использованием оператора WHILE и их эквиваленты на языке ассемблера. Отметим сходство и различие преобразований циклов, написанных на псевдокоде, в язык ассемблера и язык TOYCODE. Одинаковой в обоих случаях является общая струк- тура преобразования: используются две метки (в начале и кон- це текста создаваемого фрагмента программы) и безусловная передача управления на начало текста из точки, непосредствен- но предшествующей его концу. Различие заключается в исполь- зовании на языке ассемблера команды CMPL и большого разно- образия команд условной передачи управления, что намного уп- рощает реализацию части цикла, содержащую проверку усло- вия его окончания.
Программирование ветвящихся и циклических процессов 121 Текст на псевдокоде Текст на языке ассемблера WHILE IN-DATA >100 DO LOOP1: Замена содержимого SUM CMPL IN-DATA, # 100 суммой его предыдущего BLSS LOOPEND1 значения и копии содержи- мого IN_DATA ADDL2 IN_DATA, SUM Ввод следующего числа в READ.L IN-DATA область памяти IN-DATA BRW LOOP1 END-DO LOOPEND1: WHILE содержимое COUNT < 10 DO LOOP2: Замена содержимого SUM CMPL COUNT, # 10 суммой его предыдущего BGTR LOOPEND2 содержимого и содержи- мого COUNT ADDL2 COUNT, SUM Увеличение на 1 содержи- INCL COUNT мого счетчика COUNT BRW LOOP2 END-DO LOOPEND2: Если подлежащее проверке условие оператора WHILE со- держит одно или несколько арифметических выражений, сна- чала необходимо сформировать команды вычисления этих выра- жений, а затем команды загрузки полученных результатов в ре- гистры или области памяти. После этого требуется команда CMPL, использующая эти регистры или области памяти как опе- ранды. Рассмотрим в качестве примера оператор WHILE сле- дующего вида: WHILE (2 * VALUE) < (SUM/COUNT) DO END-DO Ему соответствует следующий фрагмент программы на языке ассемблера: LOOP: MULL3 #2, VALUE, Rl DIVL3 COUNT, SUM, R2
122 Глава 4 CMPL Rl, R2 BGEQ LOOPEND BRW LOOP LOOPEND: Отметим, что в данном случае при записи на языке ассем- блера конструкции WHILE промежуточные результаты вычис- лений временно хранятся в регистрах. Эти промежуточные дан- ные не нуждаются в наименованиях, логически связанных с ре- шаемой задачей, а поэтому нет оснований отказываться от ис- пользования регистров для их хранения. Теперь рассмотрим более полный пример. Д Пример 4.1 • Постановка задачи Исходные данные: Последовательность не равных нулю це- лых чисел (вводимых с терминала), заканчивающаяся нулем. Искомый результат: Сумма и среднее арифметическое исход- ных чисел. Поскольку этот пример не очень сложный, описание алгорит- ма решения задачи на псевдокоде приводится без коммента- риев. • Алгоритм решения задачи на псевдокоде Присвоение начального нулевого значения содержимому обла- стей SUM (сумма) и COUNT (счетчик) Ввод числа в область VALUE WHILE содержимое VALUE ( ) О DO Добавление содержимого VALUE к сумме SUM Увеличение на 1 содержимого счетчика COUNT Ввод числа в область VALUE END-DO Вычисление среднего арифметического (AVERAGE) Вывод на печать SUM и AVERAGE Конец программы • Программа на языке ассемблера ; ВЫЧИСЛЕНИЕ СУММЫ И СРЕДНЕГО ; АРИФМЕТИЧЕСКОГО ВВОДИМЫХ ЧИСЕЛ
Программирование ветвящихся и циклических процессов Г2В ; ИСХОДНЫЕ ДАННЫЕ: ПОСЛЕДОВАТЕЛЬНОСТЬ ; НЕ РАВНЫХ НУЛЮ ЦЕЛЫХ ЧИСЕЛ, ЗА КОТОРЫМИ ; СЛЕДУЕТ НУЛЬ ; ИСКОМЫЙ РЕЗУЛЬТАТ: СУММА И СРЕДНЕЕ ; АРИФМЕТИЧЕСКОЕ ИСХОДНЫХ ЧИСЕЛ .PSECT EXAMPLE, LONG SUM: .BLKL 1 ; ОБЛАСТЬ ПАМЯТИ ДЛЯ 9 СУММЫ ВВОДИМЫХ ЧИСЕЛ AVERAGE: 9 9 .BLKL 1 ; ОБЛАСТЬ. ПАМЯТИ ДЛЯ СРЕДНЕГО1 АРИФМЕТИЧЕСКОГО ВВОДИМЫХ ЧИСЕЛ COUNT: 9 9 .BLKL 1 ; ОБЛАСТЬ ПАМЯТИ ДЛЯ СЧЕТЧИКА ЧИСЛА ВВОДИМЫХ ЧИСЕЛ VALUE: 9 9 .BLKL 1 ; ОБЛАСТЬ ПАМЯТИ ДЛЯ ОЧЕРЕДНОГО ВВОДИМОГО ЧИСЛА .ENTRY EXAMPLE_4_1, 0 INIT_IO ПРИСВОЕНИЕ ИСХОДНЫХ НУЛЕВЫХ' ЗНАЧЕНИЙ ; СОДЕРЖИМОМУ ОБЛАСТЕЙ SUM И COUNT CLRL SUM CLRL COUNT ; ВВОД ЧИСЛА В ОБЛАСТЬ VALUE READ.L VALUE ; ПОКА VALUE > 0. ИЛИ VALUE < 0 ; ВЫПОЛНЯТЬ В ЦИКЛЕ LOOP: TSTL VALUE BEQL LOOPEND l ДОБАВЛЕНИЕ СОДЕРЖИМОГО VALUE К СУММЕ SUM
124 Глава 4 ADDL2 VALUE, SUM ; УВЕЛИЧЕНИЕ НА 1 СОДЕРЖИМОГО СЧЕТЧИКА ; COUNT INCL COUNT ВВОД ОЧЕРЕДНОГО ЧИСЛА В ОБЛАСТЬ VALUE READ.L VALUE BRW LOOP ; КОНЕЦ ЦИКЛА «ПОКА» ; ВЫЧИСЛЕНИЕ СРЕДНЕГО АРИФМЕТИЧЕСКОГО ; (AVERAGE) LOOPEND: DIVL3 COUNT, SUM, AVERAGE ; ПЕЧАТЬ SUM И AVERAGE PRINT.L ''’SUM, AVERAGE =’, SUM, AVERAGE $EXIT_S ; КОНЕЦ ПРОГРАММЫ .END EXAMPLE_4_1 Соответствующая программа на языке ассемблера также от- носительно проста, однако читателю, только начинающему зна- комиться с этим языком, рекомендуется внимательно изучить ее. 4.3. Ветвящиеся вычислительные процессы Запись на языке ассемблера выбора направления хода вычисле- ний ветвящегося процесса также похожа (и в то же время на- много проще) на его представление в командах TOYCODE. Об- щая схема преобразования, реализующего подобный выбор опе- ратора IF псевдокода в команды на языке ассемблера, имеет? следующий вид:
Программирование ветвящихся и циклических процессов 125 Текст на псевдокоде Текст на языке ассемблера IF условие Команды для вычисления выражений, образующих условие THEN Переход на ELSE, если условие не • • выполняется • • ELSE BRW на ENDIF • ELSE: • • ENDIF • ENDIF: Ниже приводятся два примера представления оператора IF на языке ассемблера. • Алгоритм решения задачи на псевдокоде IF содержимое области памяти VALUE > О THEN добавление содержимого области VALUE к содер- жимому области POS.SUM ELSE добавление содержимого области VALUE к содер- жимому области NEG-SUM ENDIF • Программа на языке ассемблера TSTL BLEQ ADDL2 BRW ELSE1: VALUE ELSE1 VALUE, POS-SUM ENDIF1 ADDL2 ENDIF1: VALUE, NEG-SUM
126 Глава 4 • Алгоритм решения задачи на псевдокоде IF TOTAL -COUNT >17 THEN Ввод числа в область VALUE Добавление содержимого области VALUE к содержимому области TOTAL ENDIF • Программа на языке ассемблера SUBL3 COUNT, TOTAL, R1 CMPL Rl, # 17 BLSS ENDIF2 READ_L VALUE ADDL2 VALUE, TOTAL ENDIF2: Рассмотрим еще один, более полный пример, содержащий очень простые числовые расчеты (чтобы сосредоточить внима- ние читателя не на решении задачи, а на технике составления программы). 'Д Пример 4.2 • Постановка задачи Исходные данные: Последовательность положительных це- лых чисел (оценки успеваемости студентов по 100-бальной си- стеме), за которой следует отрицательное целое число. Искомый результат: а) Выраженное в процентах количество удовлетворительных оценок (значения которых больше или рав- ны 60); б) Количество отличных оценок (оценок степени А, т. е. значе- ния которых больше или равны 90). • Алгоритм решения задачи на псевдокоде Присвоение начальных нулевых значений содержимому облас- тей памяти NUM.PASS, NAM.A и TOTAL Ввод числа в область памяти GRADE WHILE содержимое GRADE > 0 DO Увеличение на единицу содержимого счетчика TOTAL IF содержимое GRADE >60 THEN увеличение на единицу содержимого счетчика NUM_PASS
Программирование ветвящихся и циклических процессов 127 ENDIF IF GRADE >90 THEN увеличение на единицу содержимого счетчика NUM_A ENDIF Ввод числа в область памяти GRADE END-DO Вычисление выраженного в процентах количества удовлетворительных оценок Печать количества удовлетворительных оценок, выраженного в процентах, и количества отличных оценок NUM_A Конец программы Следует отметить, что в данном тексте на псевдокоде исполь- зованы два отдельных оператора IF. Такое решение несколько менее эффективно, чем при использовании вложенных операто- ров IF, где второй оператор IF включается в группу THEN пер- вого оператора IF. Первому варианту отдано предпочтение по- тому, что программы с вложенными операторами IF (особенно при глубине вложения, большей двух) труднее анализировать. Однако это не означает ни отказа от использования вложенных ветвящихся вычислительных процессов (вложенных операторов IF) в последующем изложении, ни догматической привержен- ности автора книги решению, выбранному в рассматриваемой программе. Любое из возможных решений приемлемо. Переходя к анализу приводимого ниже текста программы на языке ассемблера (результата «трансляции» программы на псевдокоде), следует помнить, что он получен в результате запи- си на языке ассемблера основных структурных элементов про- граммы на псевдокоде, а не путем описания последовательности операций алгоритма отдельными командами языка (что привело бы к созданию программы, значительно менее структурирован- ной по форме). • Программа на языке ассемблера: ; ПРОГРАММА ПОДСЧЕТА ИТОГОВ УСПЕВАЕМОСТИ СТУДЕНТОВ •.ИСХОДНЫЕ ДАННЫЕ: ПОСЛЕДОВАТЕЛЬНОСТЬ ; ПОЛОЖИТЕЛЬНЫХ ЧИСЕЛ (ОЦЕНОК УСПЕВАЕМОСТИ), ; ИСКОМЫЙ РЕЗУЛЬТАТ: А) ЗАКАНЧИВАЮЩЕЕСЯ НУЛЕМ, ; ВЫРАЖЕННОЕ В ПРОЦЕНТАХ ; КОЛИЧЕСТВО . УДОВЛЕТВОРИТЕЛЬНЫХ ОЦЕНОК (СО ЗНАЧЕНИЕМ > 60),
128 Глава 4 Б) КОЛИЧЕСТВО ОТЛИЧНЫХ ОЦЕНОК .PSECT EXAMPLE, (CO ЗНАЧЕНИЕМ >90). LONG GRADE: .BLKL 1 ; ОБЛАСТЬ ПАМЯТИ ДЛЯ ОЧЕРЕДНОЙ NUM-A: .BLKL ВВОДИМОЙ ОЦЕНКИ 1 ; ОБЛАСТЬ ПАМЯТИ ДЛЯ КОЛИЧЕСТ- TOTAL: .BLKL ВА ОТЛИЧНЫХ ОЦЕНОК 1 ; ОБЛАСТЬ ПАМЯТИ ДЛЯ ОБЩЕГО NUM-PASS: .BLKL КОЛИЧЕСТВА ОЦЕНОК 1 ; ОБЛАСТЬ ПАМЯТИ ДЛЯ КОЛИЧЕСТ- PERCENT-PASS: .BLKL ВА УДОВЛЕТВОРИТЕЛЬНЫХ ОЦЕНОК 1 ; ОБЛАСТЬ ПАМЯТИ ДЛЯ ВЫРАЖЕН- НОГО В ПРОЦЕНТАХ КОЛИЧЕСТВА УДОВЛЕТВОРИТЕЛЬНЫХ ОЦЕНОК .ENTRY EXAMPLE_4_2, О INIT-IO ПРИСВОЕНИЕ НАЧАЛЬНЫХ НУЛЕВЫХ ЗНАЧЕНИЙ СОДЕРЖИМО- МУ ОБЛАСТЕЙ ПАМЯТИ NUM-PASS, NUM-А И TOTAL CLRL NUM-A CLRL TOTAL CLRL NUM-PASS READ-L GRADE ПОКА GRADE > О ВЫПОЛНЯТЬ В ЦИКЛЕ LOOP: TSTL GRADE BLEQ LOOP-END УВЕЛИЧЕНИЕ НА ЕДИНИЦУ ; СОДЕРЖИМОГО СЧЕТЧИКА TOTAL INCL TOTAL ; ЕСЛИ GRADE > == 60, ; TO УВЕЛИЧЕНИЕ НА ЕДИНИЦУ ; СОДЕРЖИМОГО СЧЕТЧИКА NUM-PASS CMPL GRADE, #60 BLSS IS-IT-A INGL NUM-PASS ;КОНЕЦ ОПЕРАЦИЙ „ЕСЛИ* ; ЕСЛИ GRADE > = 90, ; ТО УВЕЛИЧЕНИЕ НА ЕДИНИЦУ
Программирование ветвящихся и циклических процессов 129 • СОДЕРЖИМОГО СЧЕТЧИКА NUM-A IS-IT-A: CMPL’ GRADE, #90 BLSS NOT_A INCL NLFM_A ; КОНЕЦ ОПЕРАЦИЙ „ЕСЛИ" NOT-A: READ-L GRADE BRW LOOP ; КОНЕЦ ЦИКЛА „ПОКА“ ; ВЫЧИСЛЕНИЕ ВЫРАЖЕННОГО В ПРОЦЕНТАХ КОЛИЧЕСТВА ; УДОВЛЕТВОРИТЕЛЬНЫХ ОЦЕНОК LOOP_END MULL3 #100, NUM-PASS, Rl DIVL3 TOTAL, Rl, PERCENT-PASS PRINT.L ^'ВЫРАЖЕННОЕ В ПРОЦЕНТАХ КОЛИЧЕСТВО УДОВЛЕТВОРИТЕЛЬНЫХ ОЦЕНОК В ГРУППЕ', PERCENT-PASS PRINT.L '''КОЛИЧЕСТВО ОТЛИЧНЫХ ОЦЕНОК', NUM-A SEXIT-S .END EXAMPLE_4_2 Отметим, что в этой программе для хранения исходных дан- ных и результатов регистры не используются. В последующих главах целесообразность использования регистров станет более очевидной, поскольку появляется необходимость в адресации к данным сложной структуры, а операции с содержимым регист- ров выполняются быстрее, чем с содержимым областей памяти. И все же в рассматриваемых здесь и далее программах предпо- чтение отдается областям памяти, так как в отличие от регист- ров им можно присваивать имена, отражающие содержательную часть решаемых задач. 4.4. Циклы, управляемые счетчиком В программах часто имеют место циклические вычислительные процессы, управляемые счетчиком. Наличие специальных про- граммных средств реализации такой алгоритмической структуры управления ходом вычислений не обязательно, если уже имеются средства реализации цикла с предварительной проверкой усло- 5 Зак. 483
130 Глава 4 вия (WHILE), поскольку, используя цикл WHILE, можно управ- лять циклическим вычислительным процессом посредством счет- чика. Однако команды языка ассемблера системы VAX предо- ставляют возможность просто (и удобно для программиста) реализовать циклы, управляемые счетчиком. Описанию этой воз- можности и посвящен данный раздел. Простейшее представление программными средствами цикла, управляемого счетчиком, демонстрирует оператор FOR языка Паскаль, имеющий две формы записи: 1. FOR параметp-цикла: — начальное-значение ТО конечное-значение DO операторы—тела_цикла 2. FOR параметр_цикла: — начальное-значение DOWNTO конечное-значение DO операторы_тела-цикла При использовании оператора FOR в первой форме записи параметру (индексу) цикла присваивается начальное значение, после чего значение параметра цикла сравнивается с конечным значением. Если значение параметра меньше конечного значе- ния или равно ему, выполняются операторы тела цикла. После этого управление передается в начало цикла, значение пара- метра цикла увеличивается на I и снова сравнивается с конеч- ным значением. Если значение параметра цикла опять оказы- вается меньше конечного значения или равно ему, то снова вы- полняются операторы тела цикла. Этот процесс повторяется до тех пор, пока параметр цикла не примет значение, превышающее конечное значение. При использовании второй формы записи оператора FOR выполняются аналогичные операции, однако на каждом шаге цикла значение параметра последовательно умень- шается на единицу, пока не станет меньше конечного значения. Независимо от формы представления данный оператор FOR является управляемым счетчиком оператором цикла с предва- рительной проверкой условия его окончания. Проверка условия окончания операций цикла перед очередным их выполнением предотвращает протекание циклического вычислительного про- цесса при значении параметра цикла, большем конечного. В вер- сиях языка Фортран, предшествовавших версии Фортран 77, ис- пользуется управляемый счетчиком цикл с проверкой условия его окончания после завершения операций тела цикла. Однако в языках Фортран 77, Паскаль и многих других реализован уп- равляемый счетчиком цикл только с предварительной проверкой условия. Подобный оператор цикла (FOR) включен в набор опе- раторов псевдокода, но в отличие от языка Паскаль вместо опе- раторных скобок BEGIN и END используется закрывающая скобка END-FOR.
Программирование ветвящихся и циклических процессов 131 Оператор цикла FOR состоит из четырех функционально са- мостоятельных частей: присвоения начального значения пара- метру цикла, проверки условия окончания цикла с последующей передачей управления, увеличения на 1 значения параметра цикла и возврата управления на начало тела цикла. Эти четыре части оператора цикла (подобного конструкции FOR-ТО) могут быть записаны на псевдокоде следующим об- разом: Присвоение начального значения параметру цикла IF значение параметра цикла конечного значения THEN переход на метку LOOP ELSE переход на метку LOOPEND ENDIF LOOP: Выполнение операторов тела цикла Увеличение на 1 значения параметра цикла IF значение параметра цикла конечного значения THEN переход на метку LOOP ENDIF LOOPEND: Этот фрагмент программы на псевдокоде отличается от пре- дыдущих тем, что в нем не полностью выдержаны принципы структурного программирования. Он точно моделирует оператор FOR-ТО языка Паскаль, однако в нем дважды выполняются операции проверки выполнения определенного условия и соот- ветствующей передачи управления. Такое дублирование опера- ций предпринято намеренно, поскольку оно позволяет эффек- тивно реализовать данный фрагмент с помощью особой команды VAX, рассматриваемой ниже. В набор команд VAX входит команда, обеспечивающая как единичное приращение значения параметра цикла, так и услов- ную передачу управления одному или нескольким операторам тела цикла. Символическое имя кода операции этой команды — ACBL — содержит в себе начальные буквы названий (по-анг- лийски) выполняемых операций (Add — приращение, Compare— сравнение, Branch — передача управления, а также указание на размер сравниваемых данных, Longword— длинные слова). Обобщенный формат команды ACBL имеет следующий вид: ACBL предел, шаг, параметр, адрес „перехода В этой команде значения предела и шага могут задаваться либо непосредственно константами, либо как содержимое реги- стров (при регистровой форме адресации) или длинных слов па-
132 Глава 4 мяти (при использовании символических имен в качестве адре- сов). Когда необходимо выполнить операции, эквивалентные оператору FOR-ТО, значение шага должно полагаться равным 1; при повторении же конструкции, эквивалентной оператору FOR-DOWNTO, шаг должен равняться —1. Параметр цикла представлен в команде указанием его местоположения — име- нем регистра или области памяти. Все действия, выполняемые командой ACBL, могут быть опи- саны следующим фрагментом программы на псевдокоде: Добавление к значению параметра цикла значения шага IF значение шага > О THEN IF значение параметра цикла значения предела THEN передача управления по указанному адресу ENDIF ELSE IF значение параметра цикла значения предела THEN передача управления по указанному адресу ENDIF ENDIF Отметим, что команда ACBL по логике выполняемых опера- ций намного сложнее рассматривавшихся до сих пор команд. Такие сложные команды, как ACBL, обычно отсутствуют в на- борах команд относительно небольших ЭВМ и не входят в на- боры машинных команд ЭВМ, выпускавшихся до 1963 года. Команда ACBL была включена в систему команд VAX, как легко предположить, для формирования циклов с проверкой ус- ловия их окончания после выполнения операций тела цикла. При этом она содержит операцию приращения значения параметра цикла на величину шага. Поэтому естественным является место- положение этой команды в конце списка команд, формирующих цикл. Если же необходимо реализовать обычный цикл с предва- рительной проверкой условия его окончания, то в начале упомя- нутого списка команд необходима еще одна (вторая) проверка значения параметра цикла — проверка его начального значения. Команду ACBL можно использовать для всех требуемых прира- щений значения параметра цикла и последующих проверок. Ниже показаны фрагменты программ на языке ассемблера, соответствующие двум формам оператора FOR языка Паскаль. Оператор FOR-ТО на языке Паскаль: FOR INDEX1 := INITIALl ТО LIMIT1 DO Операторы тела цикла END-FOR
Программирование ветвящихся и циклических процессов 133 Фрагмент программы на языке ассемблера: MOVL INITIAL1, INDEX1 CMPL INDEX1, LIMIT1 BLEQ LOOP1 BRW LOOPEND1 LOOP1: Команды, реализующие операторы тела цикла ACBL LIMIT1, #1, IN.DEX1, LOOP1 LOOPEND1: Оператор FOR-DOWNTO на языке Паскаль: FOR INDEX2 := INITIAL2 DOWNTO LIMIT2 DO Операторы тела цикла END-FOR Фрагмент программы на языке ассемблера: MOVL INITIAL2, INDEX2 CMPL INDEX2, LIMIT2 BGEQ LOOP2 BRW LOOPEND2 LOOP2: Команды, реализующие операторы тела цикла ACBL LIMIT2, #-1, INDEX2, LOOP2 LOOPEND2: Есть два отличия в приведенных фрагментах программ на языке ассемблера. Во-первых, во фрагменте, реализующем опе- ратор FOR-ТО, условную передачу управления выполняет команда BLEQ, а оператор FOR-DOWNTO— команда BGEQ. Во-вторых, при реализации на языке ассемблера оператора FOR-ТО шаг в команде ACBL равен 1, а оператора FOR- DOWNTO равен —1. При программировании на языке ассемблера действий обеих форм оператора FOR в случае использования констант в каче- стве начального и конечного значений параметра цикла не тре- буются команды сравнения, условной и безусловной передачи управления, нет необходимости и в метке, завершающей коман- ды цикла. Приведем несколько примеров программирования на языке ассемблера операторов FOR языка Паскаль. Текст на псевдо- коде:
134 Глава 4 FOR COUNT := 1 TO 15 DO SUM := SUM 4-COUNT END-FOR Фрагмент программы на языке ассемблера: MOVL #1, COUNT LOOP1: ADDL2 COUNT, SUM ACBL # 15, # 1, COUNT, LOOP1 Текст на псевдокоде: FOR INDEX := 100 DOWNTO 1 DO SUMSQ := SUMSQ + INDEX * INDEX END-FOR Фрагмент программы на ассемблере: MOVL #100, INDEX CMPL INDEX, LIMIT BGEQ LOOP2 BRW OUT.LOOP2 LOOP2: MULL3 INDEX, INDEX, Rl ADDL2 Rl, SUMSQ ACBL #1, #-l, INDEX, LOOP2 LOOPEND: Приведем еще один пример. Выше уже рассматривались ал- горитмы поиска наибольшего и наименьшего чисел в заданном списке чисел, поэтому для следущей задачи текст программы на псевдокоде приводится без дальнейших пояснений. Д Пример 4.3 • Постановка задачи Исходные данные: Целое число LENGTH и следующая за ним последовательность целых чисел. Длина последовательности равна значению LENGTH. Искомый результат: а) наибольшее число среди исходных чи- сел; б) наименьшее число среди исходных чисел. • Алгоритм решения задачи на псевдокоде: Ввод значения количества исходных чисел в область памяти LENGTH
Программирование ветвящихся и циклических процессов 1Эй IF содержимое LENGTH > О THEN Ввод первого числа в область памяти VALUE Присвоение содержимому областей памяти МАХ и MIN в качестве исходного значения содержимого области VALUE FOR COUNT := 2 ТО LENGTH DO Ввод очередного числа в область VALUE IF VALUE > MAX THEN присвоение содержимому области MAX значения содержимого области VALUE ENDIF IF VALUE < MIN THEN присвоение содержимому области MIN значения содержимого области VALUE ENDIF END-FOR Вывод результатов на печать ELSE вывод на печать сообщения об ошибке: „Отсутствуют исходные данные" ENDIF Конец программы Преобразуем данный текст на псевдокоде в эквивалентную программу на языке ассемблера. • Программа на языке ассемблера ; ПОИСК НАИБОЛЬШЕГО И НАИМЕНЬШЕГО ЧИСЕЛ ; ИСХОДНОЙ ПОСЛЕДОВАТЕЛЬНОСТИ ЧИСЕЛ ; ИСХОДНЫЕ ДАННЫЕ: ПОСЛЕДОВАТЕЛЬНОСТЬ ЦЕЛЫХ ЧИСЕЛ, ; КОТОРОЙ ПРЕДШЕСТВУЕТ ЦЕЛОЕ ПОЛОЖИТЕЛЬНОЕ ЧИСЛО - ; УКАЗАТЕЛЬ ЕЕ ДЛИНЫ ; ИСКОМЫЙ РЕЗУЛЬТАТ: НАИБОЛЬШЕЕ И НАИМЕНЬШЕЕ ЧИСЛА ; ИСХОДНОЙ ЧИСЛОВОЙ ПОСЛЕДОВАТЕЛЬНОСТИ .PSECT EXAMPLE, LONG LENGTH: .BLKL 1 ; ОБЛАСТЬ ПАМЯТИ ДЛЯ УКАЗАТЕЛЯ > VALUE: .BLKL 1 ДЛИНЫ ИСХОДНОЙ ЧИСЛОВОЙ ПОСЛЕДОВАТЕЛЬНОСТИ ; ОБЛАСТЬ ПАМЯТИ ДЛЯ ОЧЕРЕДНОГО » MAX: .BLKL 1 ВВОДИМОГО ЧИСЛА ИСХОДНОЙ ПОСЛЕДОВАТЕЛЬНОСТИ ; ОБЛАСТЬ ПАМЯТИ ДЛЯ НАИБОЛЬШЕГО • ИЗ ЧИСЕЛ
136 Глава 4 MIN: .BLKL I ; ОБЛАСТЬ ПАМЯТИ ДЛЯ НАИМЕНЬШЕГО ИЗ ЧИСЕЛ COUNT: .BLKL 1 : ОБЛАСТЬ ПАМЯТИ ДЛЯ СЧЕТЧИКА .ENTRY ВВОДИМЫХ ЧИСЕЛ EXAMPLE_4_3, 0. INIT.IO READ_L LENGTH • ЕСЛИ LENGTH> 0 ТО » TSTL LENGTH BGTR START BRW ERROR START: READ_L VALUE ; ПРИСВОЕНИЕ СОДЕРЖИМОМУ ОБЛАСТЕЙ ПАМЯТИ МАХ И MIN ; ИСХОДНОГО ЗНАЧЕНИЯ СОДЕРЖИМОГО ОБЛАСТИ VALUE MOVL VALUE, MAX MOVL VALUE, MIN ; ДЛЯ COUNT := 2 ДО LENGTH ВЫПОЛНЯТЬ В ЦИКЛЕ MOVL #2, COUNT CMPL COUNT, LENGTH BLEQ LOOP BRW LOOPEND LOOP: READ_L VALUE ; ЕСЛИ VALUE > MAX ; TO ПРИСВОЕНИЕ СОДЕРЖИМОМУ ОБЛАСТИ MAX ЗНАЧЕНИЯ \ ; СОДЕРЖИМОГО ОБЛАСТИ VALUE CMPL VALUE, MAX BLEQ ENDIF1 MOVL VALUE, MAX • КОНЕЦ ОПЕРАЦИИ „ЕСЛИ" ; ЕСЛИ VALUE < MIN, ; TO ПРИСВОЕНИЕ СОДЕРЖИМОМУ ОБЛАСТИ MIN ЗНАЧЕНИЯ ; СОДЕРЖИМОГО ОБЛАСТИ VALUE ENDIF1: CMPL VALUE, MIN
Программирование ветвящихся и циклических процессов 137 BGEQ ENDIF2 MOVL VALUE, MIN ; КОНЕЦ ОПЕРАЦИИ «ЕСЛИ» ENDIF2: ACBL LENGTH, #1, COUNT, LOOP ; КОНЕЦ ЦИКЛА «ДЛЯ» LOOPEND: PRINT-L "'MAXIMUM & MINIMUM =', MAX, MIN BRW ENDIF3 ; ИНАЧЕ ПЕЧАТЬ СООБЩЕНИЯ ОБ ОШИБКЕ: ; «ОТСУТСТВУЮТ ИСХОДНЫЕ ДАННЫЕ» ERROR. pRINT_L /**» ОШИБКА: ОТСУТСТВУЮТ ИСХОДНЫЕ ДАННЫЕ' • КОНЕЦ ОПЕРАЦИИ «ЕСЛИ» ENDIF3: $EXIT_S .END EXAMPLE_4_3 4.5. Дополнительные команды организации циклов В языке ассемблера системы VAX имеются команды, предназна- ченные для организации циклов, шаг изменения параметра ко- торых равен 1 или —1. Эти команды имеют символические име- на кодов операций АОВ (УВЕЛИЧЕНИЕ СОДЕРЖИМОГО СЧЕТЧИКА НА 1 И ПЕРЕДАЧА УПРАВЛЕНИЯ ПО УСЛО- ВИЮ) и SOB (УМЕНЬШЕНИЕ СОДЕРЖИМОГО СЧЕТЧИКА НА 1 И ПЕРЕДАЧА УПРАВЛЕНИЯ ПО УСЛОВИЮ). Эти команды не являются более мощным средством организации цикла на языке ассемблера по сравнению с другими командами того же назначения, однако позволяют более эффективно про- граммировать циклы, управляемые счетчиком. В большинстве случаев их можно использовать вместо команды ACBL. Команды АОВ и SOB имеют следующие форматы: AOBLSS предел, параметр ..цикла, адрес „перехода AOBLEQ предел, параметр „цикла, адрес „перехода SOBGTR параметр „цикла, адрес „перехода SOBGEQ параметр „цикла, адрес „перехода
138 Глава 4 По команде AOBLEQ выполняются те же действия, что и по команде ACBL при значении шага, равном 1: значение пара- метра цикла увеличивается на 1 и управление возвращается на начало операций тела цикла всякий раз, когда значение пара- метра оказывается меньшим или равным пределу допустимых его значений. Точно так же выполняется и команда AOBLSS. Различие только в том, что при значении параметра цикла команды AOBLSS, равном пределу, указанная передача управ- ления не выполняется. По команде SOBGTR значение параметра цикла уменьшается на 1 и управление возвращается на начало операций тела цикла во всех случаях, когда значение параметра остается большим нуля. Те же действия выполняет и команда SOBGEQ, но пере- дача управления по указанному адресу производится и в слу- чаях, когда значение параметра цикла равно нулю. При программировании на языке ассемблера действий, вы- полняемых оператором FOR-ТО, можно пользоваться командой AOBLEQ, однако для программирования действий оператора FOR-DOWNTO оказывается необходимым обращаться к услу- гам команды ACBL, поскольку команды типа SOB обладают несколько более совершенными возможностями, чем команды АОВ. С целью упрощения изложения в рассмотренных примерах действия, выполняемые обеими разновидностями оператора FOR, Программируются только посредством команды ACBL. Однако в последующих главах книги, там, где только возможно, приме- няется несколько более эффективная (с точки зрения програм- мирования) команда АОВ. 4.6. Директивы транслятора .TITLE, .SUBTITLE и .PAGE Директива .TITLE используется для присвоения имени объект- ному модулю, формируемому в результате трансляции програм- мы на языке ассемблера. Это имя никак не связано с именем файла (имя файла .OBJ), в котором хранится объектный мо- дуль. Если директива .TITLE в текст программы на языке ас- семблера не включена, то модулю присваивается имя .MAIN. Присваивать объектному модулю определенное имя с по- мощью директивы .TITLE целесообразно прежде всего для его идентификации в карте загрузки редактора связей при трасси- ровке ошибок во время выполнения. Кроме того, присвоение та- кого имени необходимо для использования средств отладки опе- рационной системы VAX (см. гл. 5). Директива .TITLE имеет следующий формат: .TITLE имя„модуля
Программирование ветвящихся и циклических процессов 139 Имя модуля записывается в виде последовательности симво- лов, количеством не более 31. Если в имени задано большее чис- ло символов, лишние символы отбрасываются (операционная си- стема их игнорирует). Директива .SUBTITLE (сокращено .SBTTL) используется для присвоения имен отдельным секциям программ на языке ас- семблера. С помощью директивы .SUBTITLE на такие логиче- ские части должна быть разбита любая программа, объемом бо- лее двух страниц. Эта директива имеет следующий формат: .SUBTITLE строка_комментария Строка комментария может содержать до 40 символов. Она печатается во второй строке каждой страницы листинга про- граммы. Она также включается в таблицу оглавлений содержи- мого файла листинга, которая предшествует листингу текста программы в этом файле. В этой таблице строка комментария размещается вместе с номером страницы и порядковым номером строки листинга, в которой директива .SUBTITLE размещается. В отдельных случаях оказывается желательным начать пе- чать некоторой (например, логически самостоятельной, новой) части программы с новой страницы. Этого можно добиться, вос- пользовавшись директивой .PAGE. У директивы .PAGE пара- метры отсутствуют. В программы на языке ассемблера могут включаться многие другие директивы. Некоторые из них рассматриваются в сле- дующих главах. Полный список и описание директив имеется в справочных материалах по языку ассемблера системы VAX (VAX-11 Macro Language Reference Manual). Выводы 1. Условная передача управления командами VAX выпол- няется примерно так же, как и в системе TOYCOM. Однако со- ответствующие команды VAX обращаются к битам-индикаторам С, V, Z и N для определения того, удовлетворено ли условие пе- редачи управления. 2. Сравнение значений двух длинных слов выполняется с по- мощью команды CMPL. Команда TSTL позволяет проверить со- держимое одного регистра или одного длинного слова памяти. 3. Безусловная передача управления может быть выполнена посредством команд BRW и BRB, которым в языке TOYCODE соответствует команда В. 4. Существует общий подход реализации средствами языка ассемблера таких операторов псевдокода, как оператора цикла с предварительной проверкой условия (WHILE), оператора ус-
140 Глава 4 ловной передачи управления (IF-THEN-ELSE), оператора цик- ла, управляемого счетчиком (FOR-ТО и FOR-DOWNTO). 5. Для организации циклов с проверкой условия его оконча- ния непосредственно после выполнения операторов тела цикла предусмотрена команда языка ассемблера ACBL. Эта же коман- да может использоваться и для циклов (подобного выполняе- мому оператором FOR языка Паскаль) с предварительной про- веркой условия его окончания. По команде ACBL значение па- раметра цикла увеличивается на 1, сравнивается с допустимым предельным значением (пределом) и осуществляется передача управления в зависимости от результата сравнения. 6. Команды SOB и АОВ обеспечивают несколько более бы- строе выполнение некоторых несложных разновидностей цик- лов, обычно реализуемых посредством команды ACBL. 7. Директива ассемблера .TITLE позволяет присваивать име- на объектным модулям, директива .SUBTITLE — озаглавливать отдельные части листинга программы, директива .PAGE — осу- ществлять прогон (без вывода информации) текущей страницы листинга с продолжением последующего вывода последующих команд, начиная со следующей страницы. Новые команды ACBL BEQL BLEQ BRB SOBGEQ AOBLEQ BGEQ BLSS BRW SOBGTR AOBLSS BGTR BNEQ CMPL TSTL Новые директивы .PAGE .SUBTITLE (или .SBTTL) .TITLE Новые термины Бит-индикатор (бит признака результата) Бит фиксации ошибки Очистка индикатора Управляемый счетчиком цикл с предварительной проверкой ус- ловия его окончания Управляемый счетчиком цикл с проверкой условия его оконча- ния после выполнения операторов тела цикла Вопросы и упражнения 1. Укажите назначение четырех первых битов PSW, 2. Какова длина (в байтах) команды BRW? 3. В чем недостаток управляемых счетчиком циклов с про- веркой условия его окончания после выполнения операторов те- ла цикла?
Программирование ветвящихся и циклических процессов 141 4. Объясните различие директив .TITLE и .SUBTITLE. 5. В чем различие команд SOBGTR и ACBL? В следующих упражнениях напишите фрагменты программ на языке ассемблера, эквивалентные приведенным фрагментам на псевдокоде: 6. IF SUM • 3 > SUPERSUM THEN печать значения AVERAGE ENDIF 7. IF KOUNT<LENGTH THEN прибавить значение NEXT к значению SUM увеличить на 1 значение KOUNT ELSE присвоить RESULT значение SUM присвоить KOUNT значение 0 (нуль) ENDIF 8. IF FIRST < SECOND THEN IF FIRST < THIRD THEN печатать значение FIRST ELSE печатать значение THIRD ENDIF ELSE IF SECOND < THIRD THEN печатать значение SECOND ELSE печатать значение THIRD ENDIF ENDIF 9. WHILE IN-DATA > 0 DO присвоить SUM значение выражения IN-DATA • IN-DATA / 2 ввести очередное число в область памяти IN-DATA END-DO 10. WHILE KOUNT < LENGTH DO увеличить на 1 значение KOUNT IF VALUE < MAX THEN прибавить значение VALUE к значению TOTAL ENDIF ввести очередное число в область памяти VALUE END-DO 11. FOR KOUNT := 1 TO 100 DO ввести очередное число в область памяти VALUE прибавить значение VALUE к значению SUM END-FOR
142 Глава 4 12. FOR INDEX := TOTAL DOWNTO 10 DO IF INDEX > 100 THEN прибавить значение INDEX к значению TOP—SUM ELSE прибавить значение INDEX к значению ВОТ-SUM ENDIF печатать значение INDEX END-FOR Для следующих задач требуется составить программы на языке ассемблера и отладить их. Сначала составьте программу на псе- вдокоде, проверьте её и затем переведите на язык ассемблера. 13. Исходные данные: последовательность положительных целых чисел и следующее за ними отрицательное целое число. Искомый результат: наибольшее и наименьшее из чисел ис- ходной последовательности. 14. Исходные данные: последовательность целых чисел, не равных нулю, завершающаяся нулем. Искомый результат: а) сумма квадратов значений чисел ис- ходной последовательности; б) выраженное в процентах количество положительных чисел исходной последовательности. 15. Исходные данные: целое число LENGTH и следующая за ним последовательность целых чисел. Длина последовательности равна LENGTH. Искомый результат: а) среднее арифметическое чисел исход- ной последовательности; б) квадрат суммы положительных чисел исходной последова- тельности. 16. Исходные данные: целое число N. Искомый результат: a) N10, если N — четное, б) N8, если N — нечетное. 17. Исходные данные: последовательность из 10 целых чисел. Искомый результат: для каждого числа N исходной последо- вательности вычислить N2, если N > 100; N3, если N < 0; N4, если 0 < N < 50; вывести на печать сообщение «ДАННЫЕ НЕ ПРИГОДНЫ ДЛЯ ОБРАБОТКИ» во всех остальных случаях. 18. Исходные данные: целое число LENGTH и следующая за ним последовательность пар целых чисел. Число пар в последо- вательности равно значению LENGTH. Первое число каждой пары может принимать значения 1,2 или 3 и является номером подмножества (подпоследовательности), которому принадлежит второе число данной пары.
Программирование ветвящихся и циклических процессов 143 Искомый результат: для каждого подмножества (1, 2 и 3) — сумма квадратов чисел (вторых чисел пар), принадлежащих этому подмножеству. 19. Исходные данные: последовательность положительных це- лых чисел и следующее за ней число —1. Искомый результат: а) выраженное в процентах количество исходных целых чисел, значения которых не выходят за пределы диапазона: 1) от 0 до 50, 2) от 51 до 74, 3) от 75 до 100; б) сообщение об ошибке, если какое-либо из исходных чисел больше 100. (Сообщение об ошибке не должно прерывать ввод и обработку следующих чисел последовательности.) 20. Исходные данные: целое число LAST. Искомый результат; сумма всех чисел, значения которых не выходят за пределы диапазона от 1 до LAST. 21. Исходные данные: целое положительное число LENGTH и следующая за ним последовательность целых чисел. Длина по- следовательности равна LENGTH. Искомый результат: а) количество появлений числа 27 в ис- ходной последовательности; б) среднее арифметическое всех чисел исходной последователь- ности, значения которых больше 100; в) сообщение «ДАННЫЕ КОРРЕКТНЫ», если значение ни од- ного из чисел исходной последовательности не выходит за пре- делы диапазона от 0 до 1000. 22. Исходные данные: три пары целых чисел. Числа первой пары обозначают минимальное и максимальное значения длины некоторой коробки, числа второй пары — минимальное и мак- симальное значение ширины; а третьей пары — аналогичные данные для высоты. Искомый результат: а) значения объемов коробок, длины сторон которых принимают с шагом 1 все возможные целочис- ленные значения в заданных пределах; б) сообщение об ошибке, если для некоторого сочетания значе- ний длины, ширины и высоты значение объема коробки оказы- вается больше 1000. (Сообщение об ошибке не должно преры- вать процесса перебора значений объемов.) 23. Исходные данные: последовательность положительных чисел и следующее за ней число —1. Искомый результат: два наибольших числа исходной после- довательности.
Глава 5 Отладчик операционной системы VAX/VMS В этой главе рассматриваются средства отладки программ, ко- торыми располагает операционная система VAX/VMS. Это очень эффективный инструмент, не заменимый для тех, кто програм- мирует на языке ассемблера системы VAX. С его помощью мож- но быстро анализировать и удобным способом управлять ходом выполнения программы. 5.1. Обобщенная характеристика отладчика Тем пользователям ЭВМ, чей опыт в области программирова- ния относится, главным образом, к языкам высокого уровня, ве- роятно, не приходилось иметь дело с системными программами отладки (отладчиками). Впрочем, в настоящее время в распоря- жение программистов начинают поступать и отладчики про- грамм на языках высокого уровня. Поскольку программисты, использующие язык ассемблера, имеют дело с очень небольшими структурными единицами дан- ных и весьма простыми командами, выполняющими элементар- ные операции, то им необходимы специальные средства, помо- гающие находить и устранять ошибки в программах. Отладчик и представляет собой такое средство. Наряду с возможностями, широко используемыми при отладке программ, написанных на языках высокого уровня, такими, как отображение множества промежуточных результатов обработки, отладчик операционной системы VAX/VMS предоставляет программисту и много других более полезных услуг. Привлекательность отладчика для программиста заключает- ся в том, что эта системная программа позволяет контролиро- вать и управлять ходом вычислительного процесса в течение все- го времени выполнения программы пользователя. Например, можно выполнять отдельные команды или временно останавли- вать выполнение программы в любой требуемой точке, а затем возобновлять выполнение с указанной нами команды. Во время останова программы можно проанализировать содержимое па- мяти или регистров и определить текущие значения переменных, а также проследить изменения этих значений, перед тем как про-
Отладчик операционной системы VAX/VMS 146 должить обработку. Чтобы при этом обеспечить обращение к ячейкам памяти по символическим именам, необходимо сооб- щить ассемблеру и редактору связей о том, что таблица симво- лических имен, обычно «ликвидируемая» к началу выполнения программы, в данном случае должна быть сохранена. 5.2. Точки останова, трассировки и наблюдения за состоянием данных В нашем распоряжении имеется ряд команд, которые исполь- зуются при работе с программой, выполняемой под управлением отладчика. Последний предоставляет возможность задавать в программе, подлежащей отладке, маркеры — так наываемые точ- ки отладки трех типов. Каждая такая точка назначается опре- деленному, выбираемому программистом, адресу программы на языке ассемблера. Наличие этих точек означает, что ячейки па- мяти, для которых они установлены, играют определенную роль для отладчика во время выполнения программы. 5.2.1. Точки останова Точки останова (breakpoints) используются для того, чтобы со- общить отладчику о необходимости останова программы при вы- полнении тех команд, адреса которых «помечены» этими точ- ками. Когда в ходе выполнения программы содержимое реги- стра счетчика команд становится равным значению адреса про- граммы, для которого установлена подобная точка, происходит останов. О необходимости включения точки останова отладчику сообщается с помощью команды SET BREAK. Эта команда имеет следующий формат: SET BREAK [/AFTER : п] адрес [DO (команда (команды))] Если не учитывать необязательные параметры, заключенные в квадратные скобки, то эта команда просто задает точку оста- нова по указанному в команде адресу, обычно представляющему собой метку (символический адрес) определенной команды про- граммы. Выполнение программы под управлением отладчика бу- дет остановлено непосредственно перед тем, как должна выпол- няться эта команда. Необязательный параметр «/AFTER:n» позволяет указать от- ладчику, что останов в заданной точке программы должен осу- ществляться после того, как управление по данному адресу бу- дет передано в л-й раз, и при каждом последующем проходе че- рез эту точку программы; при первых л — 1 проходах указанная точка останова игнорируется. Такая воможность полезна в тех случаях, когда некоторый фрагмент программы в течение опре-
146 Глава 5 деленного времени работает нормально, а затем возникают ошибки. Нет необходимости в останове выполнения программы в те периоды времени, когда программа работает нормально. Необязательный параметр «DO (команда (команды))» поз- воляет указать на необходимость выполнения в точке останова определенной последовательности команд отладчика. Мы обсу- дим команды, которые следует помещать в этом случае в переч- не команд параметра DO, в разд. 5.5.2. Как бы тщательно и глубоко ни осуществлялось планирова- ние, составление и документирование программ, все равно во время их выполнения могут быть обнаружены ошибки. Причи- нами их возникновения могут быть некорректные арифметиче- ские операции: например, деление некоторой величины на нуль. В других случаях ошибки связаны с формированием в програм- ме недопустимых к использованию адресов, что приводит к пре- кращению выполнения программы и выводу сообщения об ошиб- ке. В точках программы, в которых потенциально могут возни- кать ошибки, было бы полезно осуществлять ее останов; органи- зовать такой останов позволяет отладчик. Приводимая ниже команда отладчика обеспечивает реакцию системы на подобную особую ситуацию («сбой»), как на точку останова (вместо того, чтобы снять программу и вернуть управление операционной си- стеме, управление передается пользователю): SET EXCEPTION BREAK По истечении определенного интервала времени работы с программой под управлением отладчика программист может за- быть, в каких местах программы установлены точки останова. Для получения информации о всех установленных к данному моменту точках останова используется команда SHOW BREAK Если отдельные точки останова уже больше не нужны, но желательно продолжать выполнение программы под управле- нием отладчика, то ненужные точки останова можно исключить с помощью следующей команды: CANCEL BREAK адрес Чтобы исключить точки останова, обусловленные ошибками (сбоями) в ходе выполнения программы, можно использовать команду CANCEL EXCEPTION BREAK Если необходимо исключить из программы все точки оста- нова, то можно воспользоваться следующей командой: CANCEL BREAK/ALL
Отладчик операционной системы VAX/VMS 147 Назначение точки останова в процессе отладки станет более понятным после ознакомления (в разд. 5.4) с командами, пред- назначенными для анализа содержимого ячеек памяти и реги- стров в моменты останова выполнения программы. 5.2.2. Точки трассировки Нередко возникает ситуация, когда определенный фрагмент про- граммы не выполняется ни при каких обстоятельствах. Чтобы выяснить, достигаются ли команды такого фрагмента в ходе вы- полнения программы, можно воспользоваться предоставляемой отладчиком возможностью включить в программу так называе- мые точки трассировки (tracepoints). При работе под управле- нием отладчика и достижении ранее установленных точек трас- сировки выводится сообщение о том, что данная точка програм- мы достигнута, после чего выполнение программы продол- жается. Команда установки точек трассировки похожа на команду установки точек останова и имеет следующий формат: SET TRACE адрес В качестве операнда адрес можно использовать любой адрес программы пользователя. В качестве примера рассмотрим сле- дующую команду: SET TRACE IN_LOOP В ходе выполнения программы под управлением отладчика при достижении адреса IN_LOOP на печать или экран дисплея выводится следующее сообщение: trace at IN_LOOP С помощью точек трассировки можно проследить выполнение команд перехода, команд вызова подпрограмм или и тех, и дру- гих команд. Поскольку организация вызова подпрограмм на языке ассемблера системы VAX еще не рассматривалась, огра- ничимся анализом трассировки команд перехода. Чтобы просле- дить выполнение всех команд перехода, необходимо использо- вать следующую команду: SET TRACE/BRANCH Размещение точек трассировки в тех местах программы, где ра- нее были указаны точки останова, приводит к отмене точек оста- нова; при этом будут реализованы только точки трассировки. Для получения информации о всех установленных в программе точках трассировки используется команда SHOW TRACE
148 Глава 5 Для отмены определенных точек трассировки используются команды CANCEL с указанием в качестве операнда конкретного адреса или ключевого слова BRANCH. Для отмены всех точек трассировки эта команда записывается в следующем виде: CANCEL TRACE/ALL Предположим, например, что в программе имеется конструк- ция IF—THEN—ELSE, которая, возможно, выполняется не кор- ректно. Чтобы выяснить, какое предложение этой конструкции — ELSE или THEN — выполняется при очередной передаче управ- ления на эту конструкцию, можно поместить метку перед пред- ложением THEN и установить для нее точку трассировки точно так же, как и для уже имеющейся в программе метки предложе- ния ELSE Приводимый далее пример демонстрирует исполь- зование такой процедуры отладки. А Пример 5.1. Использование точек трассировки J IF VALUE > О THEN TSTL VALUE BLEQ ELSE ; ПРИРАЩЕНИЕ СОДЕРЖИМОМУ СЧЕТЧИКА COUNT THEN: INCL COUNT BRW ENDIF ; ELSE УМЕНЬШЕНИЕ СОДЕРЖИМОГО СЧЕТЧИКА ; COUNT НА 1 ELSE: DECL COUNT ; КОНЕЦ ОПЕРАТОРА IF ENDIF: *> В данном примере метка ELSE необходима для выполнения команды условного перехода и предусмотрена в исходном тексте программы. Что же касается метки THEN, то она включена только для регистрации выполнения предложения THEN в процессе отладки. — Прим. пер.
Отладчик операционной системы VAX/VMS 149 После того как точки трассировки будут установлены, коман- ды отладчика SET TRACE THEN SET TRACE ELSE обеспечат вывод отладчиком информации о том, какое предло- жение конструкции IF—THEN—ELSE будет выбрано при каж- дом ее выполнении. 5.2.3. Точки наблюдения за состоянием данных Использование точек трассировки позволяет проследить выпол- нение команд, находящихся в любых местах программы пользо- вателя. Иногда по непонятным для программиста причинам со- держимое ячеек памяти, предназначенных для хранения данных программы, может принимать значения, абсурдные с точки зре- ния логики решения задачи. Для выяснения причин подобных «загадочных» явлений можно остановить выполнение програм- мы в тот момент, когда меняется значение содержимого ячейки. Отладчик предоставляет такую возможность пользователю по- средством так называемых точек наблюдения за состоянием дан- ных (watchpoints). Точки наблюдения за состоянием данных могут быть уста- новлены почти для любой ячейки памяти программы пользова- теля. Соответствующая команда отладчика имеет следующий формат: SET WATCH адрес Извлечение данных из ячеек памяти, для которых установ- лены точки наблюдения за их состоянием, не приводит ни к ка- ким (с точки зрения отладчика) действиям. Однако при записи в эти ячейки нового содержимого отладчик выдает пользователю полную информацию о случившемся. Предположим, что уста- новлена точка наблюдения за состоянием данных ячейки па- мяти, адрес которой задан в программе символическим именем SUM. При записи в память по адресу SUM нового числового значения, например 27, на печать или на экран дисплея будет выведена следующая информация: write to ♦ fiAINASUM at PC «MAINALOOP+S old valu'e « 00000000 new value = 0000001B Это означает, что команда программного модуля с именем .MAIN, находящаяся в памяти по адресу LOOP4-6, записывает величину 1В (шестнадцатеричное представление десятичного числа 27) в ячейку памяти SUM, предыдущее содержимое ко-
150 Глава 5 торой равнялось нулю. В разд. 5.5.1 показано, как можно полу- чить значения данных не в шестнадцатеричной, а в десятичной форме. Заметим, что .MAIN является принимаемым по умолча- нию именем объектного модуля. Если в директиве .TITLE ука- зать имя программного модуля, то оно будет использовано вме- сто .MAIN. После вывода этих трех строк программа будет остановлена перед выполнением команды, следующей за той, которая вызва- ла изменение содержимого ячейки памяти SUM. Программа ока- жется остановленной перед выполнением команды с адресом LOOP-j-б. В разд. 5.3 показано, как можно возобновить выпол- нение программы после ее останова. К сожалению, отладчик операционной системы VAX/VMS версии 3.0, используемой в настоящее время, не позволяет уста- новить точки наблюдения за состоянием данных, находящихся в регистрах. Поскольку для реализации точек наблюдения за со- стоянием данных используется механизм защиты памяти систе- мы VAX, разработчикам последней пришлось исключить уста- новку таких точек для регистров. Для получения информации об установленных в программе точках наблюдения за состоянием данных используется команда SHOW WATCH Исключение определенной точки наблюдения за состоянием данных осуществляется с помощью команды CANCEL WATCH адрес Для исключения всех таких точек используется команда CANCEL WATCH/ALL Если требуется исключить из программы все три типа точек выполнения отладчиком определенных действий, то можно вос- пользоваться командой CANCEL ALL. Помимо этого данная команда восстанавливает первоначальные, принимаемые по умолчанию значения параметров отладчика. (Это имеет смысл только в том случае, если пользователь изменял принимаемые по умолчанию значения параметров так, как это описано в разд. 5.5.1.) 5.3. Выполнение программы под управлением отладчика Пуск выполнения программы под управлением отладчика осу- ществляется с помощью трех команд: GO, STEP и CALL. Заметим, что применение этих команд имеет смысл, только если при ассемблировании и редактировании программы, пред-
Отладчик операционной системы VAX /VMS 151 шествующих ее выполнению, были заданы необходимые для от- ладчика параметры и режимы. В разд. 5.5 описываются правила задания этих параметров и режимов. Для пуска (или повторного пуска) программы под управле- нием отладчика и ее выполнения до точки останова, точки на- блюдения за состоянием данных или полного завершения всех операций используется команда GO. Она имеет следующий формат: GO [адрес] Операнд адрес (его использование необязательно) позволяет указать любой конкретный адрес, с которого требуется начать выполнение программы. Если этот операнд не задан, выполне- ние начинается с команды, адрес которой соответствует теку- щему содержимому счетчика адреса (команды, непосредственно следующей за командой, выполненной последней перед остано- вом программы), или первой команды программы пользователя, определяемой адресом перехода на ее начало, если «сеанс» от- ладки только начинается. При использовании отладчика по умолчанию предполагается символическая адресация команд и данных. Поэтому можно на- чать или повторно инициировать выполнение программы с лю- бой ее метки (символического имени). В результате выполнения команды GO выводится одна стро- ка, указывающая символический адрес, с которого было начато выполнение программы. Текст этой строки (расположенной под командой GO) имеет следующий вид: DBG > GO LOOP start at .MAIN.\LOOP Появление сообщения "DBG>" свидетельствует о готовности отладчика к работе (готовность к приему команд отладки поль- зователя). Если адрес в команде GO представляет собой имя, указанное в директиве .ENTRY, то отладчик выдает следующее сообщение: routine start at «MAIN*\proSram-name Если необходимо выполнить только несколько команд вбли- зи той точки программы, которую требуется подвергнуть де- тальному анализу, следует использовать команду STEP. Она имеет следующий формат: JSTEP {/указатель _типа_команды} [п]
152 Глава 5 Заметим, что фигурные скобки используются здесь для ука- зания на то, что заключенная в них конструкция формата команды может отсутствовать, быть указана или даже повто- рена несколько раз. Таким образом, команда STEP может либо совсем не содержать указателей типа, либо включать после- довательность таких указателей, каждому из которых предше- ствует знак «/». В команде STEP можно задавать указатели INTO и SYSTEM. Первый указывает, что подлежащее выпол- нению число команд должно включать и команды подпрограмм; второй требует учета также и команд системных подпрограмм. Если эти указатели типа (INTO и SYSTEM) не указаны, то команда STEP обеспечит переход от точки вызова подпро- граммы непосредственно к команде, следующей за этим вызо- вом, полностью игнорируя саму подпрограмму. Следует обратить внимание, что указатель SYSTEM выпол- няет свои функции только при задании в команде STEP и ука зателя INTO. Двумя другими указателями типа, которые могут быть за- даны в команде STEP, являются OVER и NOSYSTEM. Дей- ствие первого противоположно действию указателя INTO, дей- ствие второго — указателя SYSTEM. Функции указателей OVER и NOSYSTEM реализуются системой по умолчанию. Пользова- телю предоставлена возможность задания этих указателей по- тому, что в процессе отладки допустимо использование команды, отменяющей любые функции, реализуемые системой по умолча- нию. Правила использования указанной команды изложены в разд. 5.5.1. Необязательный параметр п, который может быть задан в команде STEP, определяет число команд, которые должны быть выполнены перед принудительным остановом программы. Если этот операнд отсутствует в команде, то по умолчанию значе ние п принимается равным 1. В ответ на команду STEP отладчик выводит на экран дис- плея две строки. Первая строка содержит символический адрес команды, с которой нужно было начать выполнение программы; вторая строка — символический адрес команды, перед выполне- нием которой произошел останов, а также представление этой команды на языке ассемблера (до трансляции)—команды, подлежащей выполнению следующей. Приводимый ниже пример демонстрирует вид этой информации. А Пример 5.2. Команда STEP DBOSTEP start at ,MA!N.\OUT stepped to .MA1N.\OUT+O8s DIVL3; #0AiH.MAINAPOZ_KNT#Rx
Отладчик операционной системы VAX/VMS 153 ' Команда программы, выполняемая по команде отладчика STEP, находилась по адресу OUT и имела длину 8 байт. Сле- дующей является команда DIVL3, операнды которой заданы в виде литерала — числа 10 (представленного своим шестнадца- теричным эквивалентом — буквой А), содержимого ячейки па- мяти POZ_KNT и регистра R1. Символы W' указывают, что операнд адресуется смещением относительно содержимого счет- чика команд. Третий способ организации выполнения фрагментов про- граммы под управлением отладчика, используемый в тех слу- чаях, когда фрагмент представляет собой подпрограмму, за- ключается в применении команды CALL. Назначение команды CALL описывается после рассмотрения в гл. 10 организации подпрограмм в языке ассемблера системы VAX. 5.4. Команды EXAMINE и DEPOSIT Выше были рассмотрены средства контроля выполнения команд и состояния данных в определенных точках программы. В данном разделе показано, как можно использовать вре- менный останов выполнения программы для отображения со- держимого ячеек памяти и регистров с целью выяснения ха- рактеристик вычислительного процесса в точках останова. Для отображения содержимого ячеек памяти или регистров используется команда EXAMINE, имеющая следующий формат: EXAMINE {/указатель-типа} [адрес: [: адрес]] {, адрес [: адрес]} Назначение параметра указатель-типа команды EXAMINE описывается в данном разделе несколько позже. Остальные па- раметры команды указывают адрес данных, интересующих пользователя. Пользователь может получить содержимое одного длинного слова памяти, группы смежных длинных слов, нахо- дящихся в указанном интервале адресов, списка отдельных ячеек или групп смежных ячеек памяти. Группа отображаемых смежных ячеек памяти задается двумя адресами, разделяемыми двоеточием. Информация, получаемая пользователем в результате вы- полнения команды EXAMINE, содержит имя модуля, символи- ческое имя анализируемой области памяти (при необходимости вместе со смещением) и шестнадцатеричное представление со- держимого этой области. Рассмотрим следующий пример. (По умолчанию предполагается, что отладчик представляет резуль- таты своей работы в шестнадцатеричной системе счисления, хотя основание системы счисления можно и изменить.)
154 /лава 5 А Пример 5.3. Команда EXAMINE DBOEXAMINE KOUNT ♦MAIN.\KOUNT: 00000042 DBOEXAMINE KOUNTsKOUNT+4 «MAIN»\K0UNTs 00000042 .MAIN.XKOUNT+4! 00000244 DBG>EXAMINE •MAIN.\K0UNT+8s 00000006 Выходные данные отладчика, указанные в данном примере последними, демонстрируют, что произойдет, если в команде EXAMINE не указаны параметры: выводится содержимое обла- сти памяти размером длинное слово, следующей за последней, ранее отображенной областью того же размера. Имена регист- ров могут быть использованы в качестве корректных парамет- ров команды EXAMINE; содержимое регистров отображается в естественной последовательности возрастания порядковых но- меров регистров. Так, если в команде указать интервалы адре- сов в виде R4: R8, то пользователь получит информацию о со- держимом всех пяти регистров, принадлежащих указанному интервалу. Ограничим здесь рассмотрение указателей типа команды EXAMINE указателем INSTRUCTION; значения всех остальных необязательных параметров устанавливаются в приемлемых пределах по умолчанию. В разд. 5.5.1 будет показано, каким образом можно изменить эти принимаемые по умолчанию зна- чения параметров как для отдельных команд отладчика, так и для всех команд, которые будут выполняться в дальнейшем в течение сеанса отладки. Команда EXAMINE/INSTRUCTION осуществляет деассемблирование команды или команд, находя- щихся по адресу или адресам, указанным в списке параметров. Деассемблирование означает обратную трансляцию команды или команд из их представления в машинном коде в символи- ческую форму: машинные коды, представляющие код операции и операнды команды, заменяются символическими именами в соответствии с правилами языка ассемблера и текстом исходной программы. Это может оказаться весьма полезным для выявления при- чин возникновения ошибок во время выполнения программы. Форма представления информации, выдаваемой отладчиком по команде EXAMINE/INSTRUCTION, показана в приводимом ниже примере. Здесь осуществляется деассемблирование и ото- бражение двух команд.
Отладчик операционной системы VAX/VMS 155 Д Пример 5.4. Команда EXAMINE с указателем типа INSTRUCTION DBG> EXAMINE/INSTRUCTION ENDIF EX_5_5\ENDIF: «ACBL « «0А («01>M*EX_5_5\C0UNT>EX_5_5\L00P DBG> EXAMINE/INSTRUCTION ~ EX_5_5\ENDIF+0S: « DIVL3 » «0А»W‘EX_5_5\SUM»W*EX_5_\AUERAC6 При выполнении первой команды EXAMINE отображается команда ACBL со следующими операндами: десятичной кон- стантой 10 (представленной своим шестнадцатеричным эквива- лентом— буквой А), константой 1, символическим именем COUNT и адресом перехода LOOP. Вторая команда EXAMINE/INSTRUCTION с пробелами в поле параметров вы- водит текст следующей по порядку команды программы. При этом отображается команда DIVL3, имеющая три операнда; константу 10 (представленную своим шестнадцатеричным экви- валентом — буквой А), символические имена SUM и AVERAGE. Хотя с позиций корректной техники программирования и не- сколько рискованно, но, однако, допустимо использовать команду DEPOSIT для изменения содержимого регистров и об- ластей памяти во время останова отладчиком выполнения проч граммы. Эта команда имеет следующий формат: DEPOSIT {/указатель_типа} адрес = выражение {,выражение} На указатель типа этой команды можно пока не обращать внимания. Параметр команды позволяет поместить искомое число или последовательность чисел в память или регистры начиная с указанного адреса. Например, DBG > DEPOSIT KOUNT = 0 помещает число 0 размером длинное слово по адресу KOUNT, В следующем примере DBG > DEPOSIT KOUNT = 0, 42, 133 в область памяти, именуемую KOUNT, помещается 0, в область KOUNT + 4 — число 42 (шестнадцатеричное представление) и в область KOUNT+ 8 — число 133 (шестнадцатеричное представ- ление). Пользователь может прочесть содержимое регистров или по- местить туда данные, как если бы он имел дело с областями памяти. Однако имена с R12 по R15 не могут использоваться в данных командах отладчика и должны быть заменены на имена FP, АР, SP и PC соответственно. С помощью команды EXAMINE можно вывести для ана- лиза содержимое длинного слова состояния процессора PSL, В команде DEPOSIT в качестве адресата, принимающего на
156 Глава 5 хранение новые данные, может указываться слово состояния программы PSW, являющееся половиной PSL и представлен- ное младшими разрядами последнего. Если при первоначаль- ном обращении к отладчику запрашивается содержимое PSL, то выводится следующая информация: PSL: CMP TP FPD IS CURMOD PRVMOD IPL DU FU IU Т N 2 V С 0 0 0 0 USER USER 00 О О 0 00000 В то время как левая половина PSL содержит так назы- ваемые привилегированные данные, которые можно только чи- тать, его правая половина — PSW — может быть модифициро- вана пользователем. В правую половину можно записывать но- вые данные. Поскольку левая половина PSL (представленная его старшими разрядами) не доступна для модификации, поль- зователь должен предусмотреть в команде DEPOSIT указатель типа, обеспечивающий запись новых данных в правую половину PSL. Используемые в качестве указателя типа ключевые слова BYTE, WORD и LONG определяют размер подлежащих записи данных. Например, чтобы присвоить значение 1 биту разрешения прерывания при переполнении, возникающем во время арифме- тических операций над целыми числами, можно использовать следующую команду: DBG > DEPOSIT/WORD PSL = 20 По умолчанию предполагается, что данные представляются в шестнадцатеричной системе счисления; шестнадцатеричное чис- ло 20 представлено единицей в пятом разряде и нулями во всех остальных разрядах. Эта команда обеспечит при переполнениях, возникающих в результате выполнения операций над целыми числами, прекращение выполнения программы и вывод сооб- щения регистрации системного прерывания. В качестве указа- теля типа (выполняющего функции указателя формата данных) в команде задано ключевое слово WORD. При обращении к PSL указателями формата данных в команде DEPOSIT должны быть ключевые слова WORD или BYTE. При использовании принимаемого по умолчанию указа- теля формата данных LONG команда будет пытаться модифи- цировать привилегированную (левую) часть PSL, что недопу- стимо. Более подробно правила применения указателей формата данных команд отладчика описываются в гл. 6. Использование команды DEPOSIT требует учета определен- ных ограничений. Легко может показаться, что, если с помощью отладчика найти ошибку в программе, а затем изменить содер- жимое соответствующей области памяти с целью устранения
Отладчик операционной системы VAX/VMS 157 этой ошибки, можно получить корректную программу. В дей- ствительности для этого нужно завершить сеанс отладки, вне- сти изменения в исходный текст программы с помощью редак- тора текста, а затем повторно выполнить трансляцию програм- мы и снова проверить ее выполнение. Следует помнить, что команды DEPOSIT позволяют оперативно вносить изменения в некорректные части программы только на время сеанса отлад- ки. Если удается добиться успеха при использовании этих команд в процессе отладки, то необходимо вернуться к исход- ному тексту программы и внести в него требуемые изменения, чтобы программа в действительности стала корректной, 5.5. Вызов отладчика и выход из него В данном разделе объясняется, как инициировать работу от- ладчика, а затем завершить ее, как установить определенные значения параметров отладчика, отличные от значений, прини- маемых по умолчанию, и как использовать параметр DO при описании точек останова. Достоинства отладчика во многом определяются предусмот- ренной в нем возможностью символического обращения к об- ластям памяти. Если бы во время отладки пользователь был вы- нужден обращаться к переменным программы и командам по их машинным адресам, то такое неудобство существенно снизи- ло бы эффективность использования отладчика на практике. Чтобы избежать обращения к элементам программы по машин- ным адресам, пользователь может обеспечить доступ отладчика к таблице символических имен путем добавления к команде вы- зова транслятора ассемблера MACRO параметра ENABLE = = DEBUG. Этот параметр также обеспечивает выполнение про- граммы под управлением отладчика при выдаче команды RUN. С целью сохранения таблицы символических имен для отлад- чика используют команду JSMACRO/ENABLE = DEBUG имя.файла В гл. 10 описывается назначение символических имен, при- надлежащих другим подпрограммам, которые редактор исполь- зует вместе с объектным кодом вашего модуля. Чтобы полу- чить доступ к таким глобальным символическим именам, необ- ходимо включить в команду LINK параметр DEBUG: gLINK/DEBUG имя.файла. Если в команде MACRO задан режим DEBUG, то по коман- де RUN выводится сообщение о том, что выполнение программы происходит под управлением отладчика с указанием номера те- кущей версии последнего. Кроме того, выводится название язы-
158 Глава 5 ка программирования, на котором написана программа пользо- вателя, а также имя модуля, подлежащего отладке. Затем появляется сообщение DBG>, свидетельствующее о готовности отладчика к приему команд пользователя, после чего можно вводить любую команду отладки. Чтобы отказаться от услуг отладчика (завершить его ра- боту), пользователю достаточно выполнить одно из перечис- ленных ниже действий. Набор на клавиатуре команды EXIT и нажатие клавиш «CONTROL» и «Z» обеспечивает выход из от- ладчика, но после этого нельзя возобновить отладку без ини- циирования сеанса отладки полностью заново. Нажатие кла- виш «CONTROL» и «С», а также «CONTROL» и «Y» тоже по- зволяет выйти из отладчика, однако после этого можно возоб- новить сеанс отладки с сохранением всех установленных точек и параметров сеанса отладки. Продолжение сеанса отладки при этом может быть организовано с помощью команд CONTINUE или DEBUG. 5.5.1. Изменение значений параметров, принимаемых по умолчанию В данной главе уже несколько раз отмечалось, что некоторым параметрам команд отладчика значения присваиваются по умолчанию. В этом разделе описывается, как можно изменить эти значения. Параметр «система_счисления» принимает по умолчанию значение, соответствующее представлению данных в шестнадца- теричной системе счисления. Этот параметр определяет основа- ние системы счисления, в котором представляются входные (в команде DEPOSIT) и выходные (в командах EXAMINE и WATCH) данные отладчика. Чтобы установить новое основание системы счисления для представления данных, используется команда SET MODE ключевое _слово_систе мы ^счисления Допустимыми ключевыми словами в данном случае являются DECIMAL, HEXADECIMAL и OCTAL. (Ключевое слово OCTAL задает режим представления данных для тех пользователей мини-ЭВМ PDP-8 и PDP-11, которые привыкли к представле- нию данных в восьмеричной системе счисления и которые не хотят перестраиваться на работу с представлением данных в шестнадцатеричной системе счисления.) Для получения информации о текущей системе счисления ис- пользуется команда SHOW MODE. Значение параметра «систе- ма_счисления» может быть изменено во время выполнения от- дельной команды, если задать в ней соответствующее ключевое
Отладчик операционной системы VAX/VMS 159 слово в качестве указателя типа команды. Если, например, в данный момент значением параметра «система-счисления» яв- ляется HEXADECIMAL, то для представления содержимого ре- гистра R5 в десятичной форме достаточно воспользоваться командой EXAMINE/DECIMAL R5 Параметр формат-данных определяет формат представления входных и выходных данных отладчика. В разд. 5.4 показано, как осуществляется изменение значения этого параметра при ис- пользовании команды DEPOSIT для изменения содержимого PSL. В гл. 6 после описания других форматов представления целых чисел рассматривается более детально присвоение па- раметру отладчика значений, определяющих их формат данных. При описании команды STEP упоминалось, что указатели типа этой команды могут использоваться для задания парамет- ров INTO, OVER, SYSTEM и NOSYSTEM. Из них по умолча- нию устанавливаются OVER и NOSYSTEM. Они могут быть из- менены для всех последующих команд STEP (в течение сеанса отладки) с помощью команды SET, имеющей следующий формат: SET STEP указатель„типа {,указатель „типа} Чтобы узнать, какие параметры (указатели типа) установлены для команды STEP в данный момент, достаточно воспользовать- ся командой SHOW STEP. 5.5.2. Параметр DO команды установки точек останова Вспомним, что ключевое слово DO и присоединенный к нему список команд отладчика могут быть указаны в любой команде определения точки останова. Рассмотрим следующий пример: SET BREAK LOOP DO (EXAMINE/DECIMAL R2; GO) По этой команде назначается останов выполнения програм- мы в точке с символическим адресом LOOP. При этом указы- вается, что в момент останова необходимо вывести содержимое регистра R2, представленное в десятичной системе счисления. Указывается также, что после завершения перечисленных дей- ствий выполнение программы должно быть продолжено без за- держки. Команды в списке отделяются друг от друга точкой с запятой; список может содержать произвольное число команд. Перенос команд на строки продолжения осуществляется обыч- ным образом, а именно знак минус помещается в конце каждой строки, имеющей продолжение.
160 Глава 5 При отладке программы, содержащей сложные ошибки, про- граммиста очень скоро начинает утомлять необходимость ука- зания полных имен команд и ключевых слов. Поэтому разре- шается указывать сокращенные обозначения этих команд и слов. Ниже приводятся допускаемые отладчиком операционной системы VMS сокращения названий команд и ключевых слов Команда или ключевое слово BREAK DEPOSIT DECIMAL EXAMINE GO INSTRUCTION STEP SET SHOW TRACE WATCH Сокращенное обозначение В, D DEC E G I S SE SH T W Формирование сокращенных обозначений команд и пара- метров в операционной системе VMS базируется на предполо- жении, что если первая буква названия данной команды отли- чается от первой буквы имен всех других команд, то ничего другого и не требуется; если же названия нескольких различ- ных команд начинаются с одной и той же буквы, то к сокра- щенным обозначениям команд должны добавляться и другие буквы. 5.6. Пример сеанса отладки В этом разделе демонстрируется пример проведения сеанса от- ладки, позволяющего решить ряд несложных проблем, возник- ших при разработке небольшой программы. Отдельные фраг- менты этого примера уже использованы ранее для иллюстрации применения команд STEP и EXAMINE/INSTRUCTION. А Пример 5.5. Программа на языке ассемблера для демонстрации процесса отладки j СЕАНС ОТЛАДКИ ; ИСХОДНЫЕ ДАННЫЕ: ДЕСЯТЬ ЦЕЛЫХ ЧИСЕЛ ; РЕЗУЛЬТАТ: А) СРЕДНЕЕ АРИФМЕТИЧЕСКОЕ 1 ИСХОДНЫХ ДАННЫХ
Отладчик операционной системы VAX/VMS 161 5) ВЫРАЖЕННОЕ В ПРОЦЕНТАХ КОЛИЧЕСТВО ИСХОДНЫХ ДАННЫХ, БОЛЬШИХ НУЛЯ .TITLE EX_5_5 .PSECT EXAMPLE, LONG •.NUMBER: .BLKL 1 ; ИСХОДНЫЕ ЧИСЛА SUM: .BLKL 1 ; СУММА ИСХОДНЫХ ; ЧИСЕЛ AVERAGE: .BLKL 1 ; СРЕДНЕЕ АРИФМЕТИЧЕСКОЕ ; ИСХОДНЫХ ЧИСЕЛ PERCENT-POS: .BLKL 1 ; ВЫРАЖЕННОЕ В ПРОЦЕНТАХ ; КОЛИЧЕСТВО ПОЛОЖИТЕЛЬНЫХ ; ЧИСЕЛ COUNT: .BLKL 1 ; СЧЕТЧИК КОЛИЧЕСТВА ; ИСХОДНЫХ ЧИСЕЛ POZ-KNT: .BLKL 1 ; СЧЕТЧИК КОЛИЧЕСТВА ; ПОЛОЖИТЕЛЬНЫХ ЧИСЕЛ .ENTRY EXAMPLE_5_5, О INIT-IO CLRL SUM CLRL COUNT CLRL POZ.KNT ДЛЯ COUNT: = 1 ДО 10 ВЫПОЛНЯТЬ В ЦИКЛЕ MOVL #1, COUNT LOOP: READ-L NUMBER ; ДОБАВЛЕНИЕ NUMBER К SUM ADDL2 NUMBER, SUM ; ЕСЛИ NUMBER >0 TSTL NUMBER BLEQ ENDIF ; TO ПРИРАЩЕНИЕ СОДЕРЖИМОМУ СЧЕТЧИКА ; ПОЛОЖИТЕЛЬНЫХ ЧИСЕЛ INCL POZ-KNT ; КОНЕЦ ОПЕРАТОРА IF ENDIF: ACBL # 10, # 1, COUNT, LOOP i КОНЕЦ ЦИКЛА i ВЫЧИСЛЕНИЕ СРЕДНЕГО АРИФМЕТИЧЕСКОГО 6 Зак. 483
162 Глава 5 ; И ВЫРАЖЕННОГО В ПРОЦЕНТАХ КОЛИЧЕСТВА ; ПОЛОЖИТЕЛЬНЫХ ЧИСЕЛ DIVL3 SUM, # 10, AVERAGE DIVL3 POZ-KNT, # 10, R1 MULL3 # 100, Rl, PERCENT-POS PRINT-L ''’AVERAGE = AVERAGE PRINT-L '"PERCENT POSITIVE = ’, PERCENT-POS gEXIT_S •END Программа, приведенная в примере 5.5, была помещена в файл с именем EX55.MAR. Оуществляя пуск программы с по- мощью командного файла с именем MACD.COM, воспользуемся отладчиком для исправления ошибок, которые были внесены в текст программы. Проанализируем листинг проводимого сеанса отладки. В этом листинге комментарии пользователя чередуют- ся с данными, отображаемыми терминалом (например, экраном дисплея). • Листинг сеанса отладки программы, написанной на языке ассемблера $ SMACD PLEASE ENTER FILENAME: EX55 VAX-11 DEBUG Version 3.0-5 ZDEBUG-I-INITIAL♦ lanSuarfe is MACRO* module set to 'EX_5_5' DBG>GO routine start at EX_5_5\EXAMPLE_5_5 ?-4 ~ ~ ?1B ?5 ?-3 ?-2 ?20 ?-l ?-5 ?6 .?18’ AVERAGE = +00000000000 PERCENT POSITIVE = +00000000200 ZDEBUG-I-EXITSTATUS* is 'ZSYSTEM-S-NORMAL successful completion' DBGrZ
Отладчик операционной системы VAX /VMS 163 Результаты проведенного сеанса отладки свидетельствуют о наличии нескольких проблем, требующих решения. В соответ- ствии со значениями исходных данных их среднее арифметиче- ское должно равняться 5, а выраженное в процентах количество положительных чисел — равняться 50. Для выяснения причин несоответствия ожидаемых результатов полученным прежде все- го необходимо определить некоторые промежуточные результаты обработки путем установки точки останова сразу же после за- вершения цикла подсчета суммы исходных чисел и количества положительных чисел. Для последующего анализа эти величи- ны следует отобразить (на экране дисплея) сразу же при до- стижении данной точки останова. С целью реализации такой процедуры необходимо ввести дополнительную метку в соответ- ствующую точку программы так, чтобы можно было восполь- зоваться этой меткой при задании точки останова. Используем для этой цели метку CHECK. После включения метки CHECK в строку программы, содержащую команду DIVL3, снова попы- таемся выполнить программу $ ©MACD PLEASE ENTER FILENAME: EX55 VAX-11 DEBUG Version 3,0-5 ZDEBUG-I-INITIAL> lan^uaSe is MACRO, module set to EX_5_5 DBG>SET BREAK CHECK DBG>GO routine,start At EX—5—5\EXAMPLE—5_5 ?-4 ?16 ?5 ?-3 ?-2 ?20 ?-l ?-5 ?S ?18 break at EX_5_5\CHECK DBG>EXAMINE/DECIMAL SUM, POZ-KNT EX-5-5 \ SUM: 50 EX_5J5\PDZ_KNT5 5
164 Глава 5 Заметим, что полученные величины являются корректными. Следовательно, часть программы, связанная с выполнением цикла подсчета данных величин, корректна, по крайней мере для приведенных здесь исходных данных. Следующий шаг от- ладки заключается в пошаговом выполнении следующей за цик- лом команды программы DIVL3 SUM, =#=10, AVERAGE. По этой команде вычисляется среднее арифметическое исходных чисел. Поскольку величина SUM известна, упомянутая команда должна вычислить правильное значение среднего арифметиче- ского AVERAGE, т. е. равное 5. DBOSTEP start at ЕХ_5_5\СНЕСК stepped to ЕХ_5_5\СНЕСК+0В: DIVL3 W*EX_5_5\P0Z_KNT»#0A»R1 DBG>E/DEC AVERAGE EX_5_5\AVERAGE: 0 Как эта величина могла оказаться равной нулю? Может быть, приведенная в программе команда DIVL3 не способна выпол- нять операцию деления? В действительности это именно так, поскольку в команде нарушен требуемый порядок указания операндов, что является распространенной ошибкой начинаю- щих программистов. Делитель должен быть указан в качестве первого операнда. В следующей по порядку команде DIVL3 имеется та же самая ошибка. Поэтому необходимо прекратить выполнение программы под управлением отладчика и исправить её исходный текст путем перестановки операндов данных команд. DBG>*Z $ ED/EDT EX55.MAR 1 » A DEBUGGING SESSION *'DIVL3 ^8 DIVL3 SUM» #10» AVERAGE *S/SUM» #10/#10> SUM 48 DIVL3 #10> SUMr AVERAGE 1 substitution
Отладчик операционной системы VAX/VMS 165 * (carriage rsturnT 49 Di>VL3 POZ_KNT » #10» R1 *S/POZ_KNT« #10/#10 ».' ₽BZ_J<NT ’49 DIVL3 #10» P0Z_KNT') R1 1 substitution *EX SYSSUSERDEVIC.E s IUCC^ »RWSEBESTAJEX55»MAR iZ 54 lines Наивно полагая, что теперь в программе нет ошибок, попытаем- ся ее выполнить без задания точек останова. « RMACD PLEASE ENTER FILENAMES ЕХ55 VAX-11 DEBUG Version 3.0-5 XDEBUG-I-INITIAL. lanSuaSe is MACRO» module set to 'EX_5_5' DBG>G routine Start at EX_5_5\EXAMPLE_5_5 ?-4 ' ~ — — ?ie ?5 ?-3 ?-2 ?20 ?-l ?-5 ?B ?18 AVERAGE = +00000000005 PERCENT POSITIVE = +00000000000 7DEBUG-I-EXITSTATUS» is 'ZSYSTEM-S-NDRMQl^ normal successful completion' DBG>AZ Снова неприятности! Хотя теперь и получено правильное значе- ние среднего арифметического, однако выраженное в процентах количество положительных чисел оказывается равным 0 вместо ожидаемого 50. Требуется задать точку останова, чтобы в по- шаговом режиме исследовать выполнение вызывающей подозре- ние части программы,
166 Глава 5 * R ЕХ55 VAX-11 DEBUG Version 3»0-5 XDEBUG-Г-INITIAL > lan</ua</e is MACRO i module set to 'EX_5__5' DBG>SET BREAK CHECK DBG>GO routine start at Ea_5_5\EXAMPLE^5__5 ?-4 ?16 ?5 ?-3 ?-2 , ?20 ?-l ?-5 ?6 ?18 break at EX_5_5\CHECK DBG>S start at EX_5_5\CHECK stepped to EX_5_5\CHECK+08? DIVL3 #0A >WAEX_5__5.\P0Z__KNT »R1 Посмотрим теперь, какое значение имеет переменная POZ-KNT, чтобы быть уверенными, что это правильная вели- чина 5. DBG > Е POZ-KNT EX-5-5\POZ_KNT: 00000005 Всё правильно. Поэтому выполним ещё одну команду и посмот-». рим содержимое регистра R1. DBG>S start at ЕХ_5_5\СНЕСК+08 stepped to EX__5_5\CHECK+OEs MULL3 #00000064,R1EX_5_5\PERCENT—POS DBG>E Rl RU 00000000 Содержимое регистра Rl равно 0. Это является напоминав нием о том, что производится деление целых чисел. В самом
Отладчик, операционной системы VAX/VMS 167 DBG>*Z $ ED/EDT EX55.MAR '1 f A DEBUGGING SESSION *'MULL3 50 MULL3 #100> Rl 1 PERCENT_POS 49 DIVL3 «101 POZ_KNT , Rl *R 1 line deleted MULL3 #100» POZ_KNT» Rl DIVL3 #10» Rl , PERCENT_POS 50 *D MULL3 «100» Rl »•• PERCENT_POS 1 line deleted 51 PRINT-L "AVERAGE «'» AVERAGE *EX SYSSUSERDEVICEsCUCCS♦RWSEBESTA1EX55<MAR S3 54 lines $ ©MACD PLEASE ENTER FILENAME; EX55 VAX-11 DEBUG Version 3t0-5 . ZDEBUG-I-INITIAL> lan*ua*e is* MACRO» module set to 'EX 5 5' DBG>GO routine start at EX_5_5\EXAMPLE~5_5 ?-4 ~ ?16 ?5 ?-3 ?-2 ?20 ?-l ?-5 ?6 ?18 AVERAGE = +00000000005 PERCENT POSITIVE = +00000000050 7.DEBUG-I-EXITSTATUS » is 'XSYSTEM-S-NORMAL > normal successful completion DBG>AZ
168 Глава 5 деле, результатом деления 5 на 10 и должно быть 0 Чтобы исправить эту ошибку, необходимо реорганизовать операции, связанные с вычислением целочисленного значения количества положительных чисел, выраженного в процентах. Для этого сна-* чала содержимое поля POZ-KNT следует умножить на 100, а затем разделить на 10. Теперь еще раз попытаемся выполнить программу. Наконец получены правильные результаты. 5.7. Команда DUMP Другим средством, иногда весьма полезным для отладки про- грамм, является команда DUMP, предусмотренная в системе управления вводом-выводом операционной системы VMS, Команда DUMP выводит копию содержимого регистров и опре- деленной области памяти, используемые выполняемой програм- мой. Команду DUMP можно применять для выявления некор- ректных модификаций команд программы и содержимого обла- стей памяти. Она может быть помещена в любых точках про- граммы, как и любая другая выполнимая команда. Команда DUMP имеет следующий формат: DUMP начальный _ad pec, конечный-адрес Оба этих адреса могут быть заданы в соответствии с любым допустимым в системе VAX режимом адресации. Содержимое областей памяти выводится по команде DUMP строками, каждая из которых включает восемь длинных слов. 32 байта информации, отображаемой в каждой строке, разме- щаются справа налево с указанием адреса первого байта в пра- вом конце строки. Начальный адрес отображается в первом вы- водимом длинном слове, а конечный адрес — в последней строке. Вместо демонстрации выходных данных, получаемых в ре- зультате выполнения команды DUMP, читателю рекомендуется проверить эффективность ее использования, применив эту команду к последней из написанных им программ. Выводы 1. Отладчик операционной системы VAX/VMS представляет собой эффективное средство анализа хода выполнения и отлад- ки программ, написанных на языке ассемблера. о Сказанное справедливо только для выполнения деления при использо- вании так называемой арифметики целых чисел (результат деления целого числа на целое есть целая часть частного). — Прим. ред>
Отладчик, операционной системы VAX/VMS 169 2. Точки останова представляют собой «маркеры» адресов команд программы, при достижении которых в ходе выполне- ния программы происходит ее останов. 3. Точки трассировки представляют собой «маркеры» адре- сов команд, при достижении которых выводится на печать (или экран дисплея) соответствующее сообщение отладчика, после чего выполнение программы продолжается. 4. Точки наблюдения за состоянием данных представляют собой «маркеры» адресов размещения данных. При изменении содержимого областей памяти, для которых установлены такие точки, производится вывод на экран дисплея (или печать) ста- рого и нового содержимого этих областей, а также адреса команды, выполнение которой обуславливает указанное приме- нение. 5. Точки останова, трассировки и наблюдения за состоянием данных устанавливаются с помощью команды SET, удаляются с помощью команды CANCEL и отображаются по команде SHOW. 6. Выполнение программы под управлением отладчика ини- циируется командами STEP или GO. 7. Команда EXAMINE используется для просмотра содер- жимого областей памяти или регистров во время останова вы- полнения программы. Команда DEPOSIT может применяться для записи нового содержимого в области памяти или в регист- ры во время останова программы. 8. Чтобы воспользоваться отладчиком, нужно указать соот* ветствующую информацию в командах MACRO и LINK. 9. Значения параметров система_счисления, формат_данных и указатель типа команды STEP могут быть изменены по сравне- нию с принимаемыми по умолчанию значениями с помощью команды SET. Новые команды CALL DEPOSIT SET CANCEL EXAMINE SHOW CONTINUE EXIT STEP DEBUG GO Новые термины Деассемблирование Параметр «система счисления» Параметр «формат данных»
170 Глава 5 Точка наблюдения за состоянием данных Точка останова Точка трассировки Вопросы и упражнения 1. Объясните назначение параметра DO команды SET BREAK. 2. Для какой цели предусмотрен параметр AFTER в команде SET BREAK? 3. В чем различие между командами GO и STEP? 4. Опишите все указатели типа, которые можно использовать в команде STEP. 5. Почему команду DEPOSIT нужно применять очень осто- рожно? 6. Что произойдет, если в команде EXAMINE не указать ни- каких параметров? 7. Почему нужно задавать параметр формат-данных в команде DEPOSIT, используемой для модификации слова со- стояния процессора PSL? 8. Для чего используется команда DEBUG операционной си- стемы VMS? 9. В чем различие между выходом из отладчика (прекра- щением работы отладчика) нажатием клавиш «CONTROL» и «С» и использованием команды EXIT? 10. Введите в машину VAX программу примера 4.2. Допол- ните программу метками NEWMAX и NEWMIN в тех строках программы, которые содержат команды MOVL VALUE,МАХ и MOVL iVALUE,MIN соответственно. Установите точки трас- сировки в местах программы, имеющих символические адреса NEWMAX и NEWMIN. Задайте точку наблюдения за состоя- нием данных по адресу COUNT, а точку останова по адресу LOOPEND. Выполните теперь программу под управлением от- ладчика со следующими исходными данными 6, 5, 3, 7, 2, 6, 1. Когда содержимое области памяти COUNT изменится в ше- стой раз (станет равным 6), организуйте пошаговое выполнение остальной части программы, по одной команде в каждом шаге, внимательно наблюдая форму представления деассемблирован- ных команд и используя команду EXAMINE для отображения содержимого слова состояния процессора PSL после каждого выполнения команды CMPL. Затем исключите все установленные точки отладки, устано- вите точку останова по адресу NEWMAX и повторно выполните программу с теми же самыми исходными данными. Каждый раз при достижение точки останова выведи, е содержимое областей памяти MIN, МАХ и COUNT. Помимо этого при первом оста-
Отладчик, операционной системы VAX/VMS 171 нове выведите первые три команды, расположенные в тексте программы, начиная с символического адреса ENDIFL 11. Поместите команду DUMP в программу, приведенную в примере 4.2, непосредственно перед командой $EXIT_S, ис- пользуя в качестве параметров команды символические адреса GRADE и LOOP.END + 20. Затем получите листинг ассембли- рования программы, после этого выполните программу. Внима- тельно сравните машинный код, изображенный на листинге, с выходными данными, полученными в результате выполнения команды DUMP.
Глава 6 Целые числа различных размеров В системе VAX могут обрабатываться целые числа различных размеров (длины). Для простоты изложения до сих пор рас- сматривались команды, оперирующие с целыми числами разме- ром длинное слово. Однако система VAX располагает суще- ственно большим числом команд, предназначенных для обработ- ки целых чисел других размеров. В этой главе рассматриваются целые числа других размеров, не равных длинному слову, а также недесятичные константы и особенности использования ин- дикатора переполнения, устанавливаемого в поле признака ре- зультата слова состояния процессора после выполнения опреде- ленных команд. Хотя в главе вводится большое число новых команд и директив, большая часть из них представляет собой только новые модификации уже знакомых читателю команд, рассмотренных в предыдущих главах. 6.1. Форматы представления целых чисел Целые числа размером длинное слово имеют естественное с точ- ки зрения архитектуры системы VAX внутреннее представление, поскольку их длина совпадает с размером (числом разрядов) регистров процессора. Однако часто возникает потребность в размещении в памяти целых чисел других размеров: например, может потребоваться большой массив целых чисел, причем зна- чения, присваиваемые каждому элементу массива, не превы- шают величины, которая могла бы быть записана в двухбайто- вом поле. Если имеется возможность размещать числа в полях размеров 2 байта, т. е. в словах памяти, то понадобится в 2 раза меньший объем памяти по сравнению со случаем представления Целых чисел длинными словами. Реже возникает необходимость хранить в памяти числа, размер которых превышает длинное слово. Все же иногда это может оказаться удобным, например, для пересылки данных блоками, размер которых превышает длинное слово. В главах 9, 10 и 11 рассматриваются примеры использования целых чисел, размер которых не равен длинному слову. Таким образом, имеется ряд основательных причин для включения в архитектуру системы VAX средств обработки це-
Целые числа различных размеров 173 лых чисел, размер которых больше и меньше длинного слова. Во всех командах, манипулирующих целыми числами различ- ных размеров, одна из букв символического обозначения кода операции указывает размер операнда. Как указано в гл. 3, для представления целых чисел используются форматы четырех ти- пов: BYTE (байт), WORD (слово), LONGWORD (длинное сло- во), QUADWORD (двойное длинное слово). Как в машинных командах, так и в директивах транслятора буквой символиче- ского обозначения кода операции, определяющей размер опе- ранда, является В, W, L или Q для целых чисел размером байт, слово, длинное слово или двойное длинное слово соответственно. 6.1.1. Директивы для работы с целыми числами, размер которых не равен длинному слову В системе VAX наименьший размер (количество разрядов) имеют такие целые числа, которые представлены в формате BYTE. Директива .BLKB используется для резервирования од- ного или нескольких байтов памяти с целью возможного после- дующего размещения одного или нескольких целых чисел раз- мером байт. Эта же директива присваивает резервируемой па^ мяти нулевое содержимое (записывая в нее двоичные нули). Директива .BYTE предназначена для резервирования одного байта памяти с записью в эту область любого целого числа, указываемого в качестве операнда этой директивы. Директива .BLKW предназначена для резервирования бло- ков памяти, используемых для размещения целых чисел раз- мером слово каждое, а директива .WORD для выделения слова памяти целым числам такого же формата и размещения в ка- ждом таком слове целого числа, указываемого в качестве опе- ранда директивы. Блоки памяти для размещения целых чисел размером двой- ное длинное слово каждое могут быть зарезервированы с по- мощью директивы .BLKQ °. Директива .QUAD резервирует два смежных длинных слова памяти и помещает в них целое число, задаваемое в качестве ее операнда. Если для обработки целых чисел размером байт, слово или длинное слово в системе VAX-11 имеется обширный набор команд, то для работы с целыми чис- лами размером двойное длинное слово количество команд весь- ма ограниченно. Рассмотрим несколько примеров использования описанных директив. ° Подобно директиве .BLKB и .BLKL, директивы .BLKW и .BLKQ не только резервируют память, но и присваивают зарезервированным областям исходное содержимое, равное нулю. — Прим, ред.
174 Глава 6 А Пример 6.1. Директивы резервирования памяти и размещения в ней целых чисел, размер которых не равен длинному слову BIG_NUMBS: •BLKQ 25 LITTLE_ONES: .BL KB 35 SUM_W: .WORD 427 KOUNT: •BYTE 42 BIG-VALUE: •QUAD 1000000000000000 Метка BIG-NUMBS представляет собой символический ад- рес первого из 25 двойных длинных слов памяти, каждому из которых присваивается нулевое значение. Данная директива .BLKQ резервирует область памяти размером 200 байт. Метка LITTLE-ONES — символический адрес первого из 35 байт па- мяти, каждому из которых присваивается нулевое значение, SUM-W — символический адрес слова памяти, в которое поме- щается целое число 427, а метка KOUNT — символический адрес байта памяти, в которой помещается целое число 42. Метка BIG-VALUE адресует ячейку памяти, резервируемую для це- лого числа размером двойное длинное слово. Приведенная выше директива .QUAD не только резервирует эту область памяти, но и записывает в нее целое число, равное 1015. 6.1.2. Команды пересылки и выполнения арифметических операций над целыми числами, размер которых не равен длинному слову В системе VAX многие команды, выполняющие однотипные опе- рации над целыми числами различных размеров, имеют одина- ковый формат, отличающийся только одной буквой кода опе- рации, специфической для каждого формата представления це- лых чисел. Это справедливо, например, для команд очистки ячеек памяти CLRx. Команда CLRL очищает длинное слово па- мяти и записывает в него целое число, равное нулю. Команда CLRB выполняет ту же самую операцию для байта памяти, команда CLRW — для слова памяти, а команда CLRQ— для двойного длинного слова. Команда CLRQ иногда используется для очистки двух смежных длинных слов, четырех смежных слов или восьми смежных байтов памяти. В приводимом ниже при- мере одна команда CLRQ очищает (записывает двоичные нули) одновременно две области памяти SUM и COUNT: SUM: .BLKL 1 COUNT: .BLKL 1 CLRQ SUM
Целые числа различных размеров 175 Если при использовании команды CLRx операнд находится в регистре, причем х задается в виде В или W, то оставшаяся часть содержимого регистра сохраняется без изменения. Если, например, регистр R4 содержит шестнадцатеричное число 12345678 и выполняется команда CLRW R4 то в результате в регистре R4 окажется 12340000. Подобно команде CLRx, в символическом обозначении кода операции команды MOVx имеется одна (последняя) буква, ука- зывающая, какой из четырех возможных форматов представ- ления целых чисел, допустим к использованию. Команда MOVB пересылает содержимое байта памяти, команда MOVW — слова памяти и команда MOVQ — двойного длинного слова. Послед- няя может оказаться удобной для пересылки смежных (разме- щенных в памяти последовательно друг за другом) целых чи- сел меньших размеров. Например, если метка LIST определяет символический адрес первого из четырех слов памяти, то команда MOVQ LIST, R6 перешлет длинное слово, находящееся по адресу LIST, в регистр R6, а длинное слово, находящееся по адресу LIST+ 4, — в ре- гистр R7. Как и в случае использования команды CLRx, в командах MOVB или MOVW при указании регистра в качестве операн- да-приемника содержимое старших разрядов регистра сохра- няется без изменения. Если, например, в регистре R4 находится шестнадцатеричное число 3F56B831, а в области памяти с сим- волическим адресом VALUE (предназначенной для размещения целого числа размером байт) — шестнадцатеричная величина 7F, то в результате выполнения команды MOVB VALUE, R4 содержимое регистра R4 будет равно 3F56B87F. (Не следует забывать, что числа, занимающие несколько байт, всегда запи- сываются в обратном порядке, т. е. начиная с конца поля, пред- назначенного для их размещения.) Если содержимое регистра требуется полностью заменить целым числом, размером байт или слова, следует использовать, одну из команд преобразова- ния размера целого числа, рассматриваемых в разд. 6.1.3. При истюльзовании регистра в качестве операнда-источника команд, оперирующих с целыми числами размером байт или слова, обработке подлежит только первый байт или первое слово содержимого регистра.. Например, команда MOVB R4, VALUE
17R Глава 6 выбирает только первый байт (байт младших разрядов) содер- жимого регистра R4 и пересылает его в область памяти, име- нуемую VALUE. В общем случае код операции определяет размер операндов независимо от того, какие операнды указаны в команде. На- пример, команда MOVW FIRST, SECOND пересылает слово данных из области памяти с символическим адресом FIRST в область памяти с символическим адресом SECOND, независимо от того, каким образом определены адре- суемые этими метками поля памяти. FIRST может быть меткой директивы .BLKB, a SECOND — меткой директивы .QUAD, но тем не менее пересылаются два байта данных. Это справедливо и при работе с регистрами. Размер регист- ра не имеет никакого отношения к размеру поля, используемому при выполнении команды. Как было показано ранее, команда MOVB с указанием регистра в качестве операнда имеет дело с байтом младших разрядов содержимого регистра. Команда MOVQ, использующая регистр в качестве операнда, на самом деле адресуется паре регистров. Так, команда MOVQ R4, AREA пересылает содержимое двух регистров R4 и R5 в область па- мяти с символическим адресом AREA. MNEGx— новая команда пересылки. Она перемещает целые числа точно так же, как и команда MOVx, однако при этом знак пересылаемого числа изменяется на противоположный. Следо- вательно, команда MNEGL SUM, SUM изменяет значение содержимого длинного слова памяти с адре- сом SUM на противоположное по знаку независимо от исход- ного содержимого данного слова. Команда MNEGx может быть также использована для изменения на противоположное по зна- ку значение содержимого одной области памяти с последующей записью этого нового значения в другую область памяти. Команда MNEGx имеет модификации для работы с целыми чис- лами размером байт, слово, длинное слово. Однако для работы с целыми числами размером двойное длинное слово подобная команда не предусмотрена. Десять команд выполнения арифметических операций —• INCx, DECx, ADDx2, ADDx3, SUBx2, SUBx3, DIVx2, DIVx3, MULx2, MULx3 —имеют модификации, используемые для об- работки целых чисел размером байт, слово и длинное слово. В системе VAX не предусмотрены подобные команды для обра-
Целые числа различных размеров . 177 ботки целых чисел размером двойное длинное слово. Как и при выполнении команд пересылки, оперирующих целыми числами размером байт и слово и использующих регистры в качестве операндов-приемников, команды выполнения арифметических операций над целыми числами сохраняют без изменения содер- жимое дополнительной (по отношению к обрабатываемому чис« лу, размер которого задается кодом операции команды) части разрядов регистра. Например, команда SUBB2 PART, R7 вычитает целое число, занимающее байт памяти с символиче- ским адресом PART из байта младших разрядов содержимого регистра R7 и помещает результат операции в этот же байт младших разрядов, сохраняя без изменения три байта старших разрядов содержимого регистра R7. Для обработки целых чисел могут оказаться весьма полез- ными две дополнительные команды выполнения арифметических операций: EDIV и EMUL. Команда EDIV (расширенное деление) делит целое число размером двойное длинное слово на целое число размером длин- ное слово. В команде используются 4 операнда: в первом ука- зывается делитель (целое число размером длинное слово), во втором — делимое (целое число размером двойное длинное сло- во), в третьем — область памяти, предназначенная для разме- щения частного, представленного в формате длинного слова, а в четвертом — такая же область для размещения остатка от деления. Например, команда EDIV KOUNT, SUM, RATIO, REMAIN делит содержимое двойного длинного слова с адресом SUM на содержимое длинного слова с адресом KOUNT и помещает частное в длинное слово с адресом RATIO а остаток —в длинное слово с адресом REMAIN. Команда EMUL (расширенное умножение) также имеет 4 операнда. В первом операнде указывается множитель (целое число размером длинное слово), во втором — множимое (целое число размером длинное слово), в третьем — «второе слагаемое» и в четвертом — двойное длинное слово памяти, в которое по* мещается результат операции умножения удвоенной длины. Так называемое второе слагаемое содержит расширение знака до старшего разряда двойного длинного слова и добавляется к результату выполнения операции умножения. Преобразование с расширением бита знака означает, что целое число «расши- ряется» до требуемого размера путем помещения копии бита ° По сравнению с длиной делителя и делимого, Прим, перев.
178 Глава 6 знака во все незаполненные старшие разряды поля представ- ления данных. Такая процедура обеспечивает сохранение тре- буемого знака числа. Использование операнда «второе слагаемое» позволяет весь- ма удобно перемножать даже большие целые числа. Вспомним, что перемножение больших чисел ручным способом требует мно- жества операций умножения множимого на относительно не- большие числа и последующего сложения результатов этих опе- раций. В качестве примера рассмотрим следующую команду EMUL: EMUL QUANTITY, VALUE, #0, ITEM-VALUE При выполнении этой команды производится умножение це- лого числа размером длинное слово, находящегося в области памяти с адресом QUANTITY, на содержимое длинного слова памяти с адресом VALUE, а результат дополняется нулями и л полученное при этом целое число размером длинное слово за- писывается в область памяти с адресом ITEM-VALUE. Посколь- ку перемножаются два одиночных длинных слова, то в качестве второго слагаемого используется нуль. Команда EDIV оказывается особенно удобной в. тех случаях, когда она следует непосредственно за командой EMUL. Напри- мер, для вычисления значения выражения FIRST-SECOND/ THIRD, в котором все три переменные принимают значения целых чисел размером длинное слово, можно воспользоваться следующей последовательностью команд: Д Пример 6.2. Использование последовательности команд EMUL — EDIV. EMUL FIRST, SECOND, #0, TEMP-QUAD EDIV THIRD, TEMP_QUAD, QUO, REM В программах, для которых крайне важно эффективное ис- пользование памяти, целесообразно размещать флажки и счет- чики в областях памяти, размеры которых равны байту или слову. В подобных случаях возникает необходимость сравнивать и тестировать содержимое таких областей. Команды тестирова- ния и сравнения в системе VAX имеют соответствующие моди- фикации для работы с целыми числами размером байт и слово. Команда TSTB тестирует содержимое байта памяти, а команда TSTW — содержимое слова памяти. Обе команды присваивают единичные значения соответствующим битам признака резуль- тата в PSW, что позволяет выполнять операции условного пе- рехода, используя результат тестирования. Команды СМРВ и CMPW сравнивают содержимое двух байтов и двух слов памяти соответственно. Они действуют точно так же, как и использо- ванная ранее команда CMPL.
Целые числа различных размеров 179 Рассмотренные в гл. 4 циклы, управляемые счетчиком, пред- полагают использование длинных слов для представления зна- чений индекса (параметра цикла): текущего, начального и ко- нечного. В большинстве случаев, однако, количество итераций цикла относительно невелико: почти никогда не выходит за гра- ницы диапазона значений целого числа размером слово (-32768--- + 32767) и часто даже принадлежит диапазону зна- чений целого числа размером байт (—128-?- + 127). Целые чис- ла размером байт или слово можно использовать для организа- ции циклов с помощью команд АСВВ или ACBW. В команде АСВВ начальное, текущее и конечное значения параметра цикла представляются операндами, являющимися целыми числами или переменными целого типа размером байт. В команде АСВВ для тех же целей используются целые числа или переменные целого типа размером слово. Обе команды выполняются точно так же, как и команда ACBL. Применение команды ACBW иллюстри- рует следующий пример. А Пример 6.3. Использование команды ACBW INDEX: -BLKW 1 ; ДЛЯ INDEX: = 1 до 100 ВЫПОЛНЯТЬ В ЦИКЛЕ MOVW LOOP: #1, INDEX ACBW #100, #1, INDEX, LOOP • КОНЕЦ ЦИКЛА В данном примере при реализации конструкции FOR для языка высокого уровня средствами языка ассемблера началь- ное, текущее и конечное значения параметра цикла представ- ляются целыми числами размером слово. Размер целых чисел (констант), определяющих начальное и конечное значения па- раметра цикла, транслирующая программа (ассемблер) уста- навливает в результате анализа текста транслируемой программы (в данном случае анализируя код операции соответствующей команды).
180 Глава 6 Не рекомендуется использовать команду АСВВ, если нет абсолютной уверенности в том, что параметр цикла никогда не примет значений, меньших —128 и больших 127. Даже если это требование выполняется в момент написания программы, в дальнейшем при модификации программы оно может быть нарушено. 6.1.3. Команды преобразования форматов данных Согласно изложенному выше, целые числа могут быть представ- лены посредством четырех различных форматов (иметь четыре разных размера). При использовании таких чисел в качестве операндов команд ассемблера программисту могут потребовать- ся манипуляции с числами разных размеров (форматов). На практике часто возникает необходимость преобразования целого числа одного размера в эквивалентное целое число другого размера. Обычно для этой целив программу включаются соответствую- щие процедуры преобразования целых чисел. Если целое число большей длины преобразуется в целое число меньшей длины, то биты старших разрядов просто отбрасываются. Если не все отбрасываемые биты положительного числа являются двоич- ными нулями, а отрицательного числа — двоичными единицами, то в слове состояния процессора устанавливается признак пере- полнения, т. е. соответствующему биту PSL присваивается еди- ничное значение, что указывает на потерю части значения пре- образуемой величины. В разд. 6.6 показано, как можно прове- рить, установлен ли признак переполнения. При преобразовании целых чисел меньшего размера в целые числа большего размера производится «распространение» бита знака до левого края поля большего размера. Команды CVTxx (преобразование формата) используются для преобразования формата представления целого числа с заполнением дополни- тельных старших разрядов числа битом знака (sign-extended size conversions). Коды операции соответствующих команд при- ведены ниже. Код операции | Описание CVTBW Преобразование байта в слово CVTBL Преобразование байта в длинное слово CVTLB Преобразование длинного слова е байт CVTLW Преобразование длинного слова в с^озо CVTWB Преобразование слова в байт CVTWL Преобразование слова в длинное слово
Целые числа различных размеров 181 Если требуется переслать целое число в область памяти боль- шего размера с записью в дополнительные старшие разряды принимающего поля двоичного нуля вместо бита знака (нуля для положительных чисел, единицы — для отрицательных), то используется преобразование с «распространением» двоичного нуля (zero-extended conversion). Подобное преобразование вы- полняется с помощью команд MOVZxx. Команда MOVZBL пе- ресылает число размером байт в область памяти размером длин* ное слово, заполняя нулями старшие 24 разряда этой области. Команда MOVZBW пересылает число размером байт в область памяти размером слово, заполняя нулями старшие 8 разрядов принимающего поля. Команда MOVZWL пересылает число раз- мером слово в область памяти размером длинное слово, запол- няя нулями старшие 16 разрядов принимающего поля. Данные команды используются для организации обработки числовых ве- личин без знака. В гл. 15 выполнение операций над величинами без знака рассматривается более детально. Для иллюстрации преобразований форматов с «распростра- нением» бита знака и нуля рассмотрим следующий пример. А Пример 6.4. Преобразование форматов целых чисел MOVB # —5, PLACE MOVZBL PLACE, Rl CVTBL PLACE, R2 | 11111011 | :PLACE '| 000000000000000000000000111110111 :R1 | 1111111111111111111Ш11Ш110111 :R2. Обратите внимание на размещение меток справа от схемати- ческого изображения областей памяти. Этим подчеркивается тот факт, что каждая метка является символическим адресом млад- шего байта соответствующей многобайтовой области. 6.1.4. Отладчик и целые числа, размер которых не равен длинному слову По умолчанию параметр отладчика тип-данных имеет значение LONGWORD (длинное слово). Это означает, что команды от- ладчика DEPOSIT и EXAMINE оперируют целыми числами или переменными целого типа размером длинное слово при записи информации в память и извлечении из нее соответственно. Та- кой режим работы недопустим, когда для тех же целей необхо- димо оперировать числами, размер которых не равен четырем байтам. Параметру отладчика тип-данных можно присвоить зна^
182 Глава б чение «байт», «слово» или «длинное слово», используя команду SET TYPE с ключевыми словами BYTE, WORD или LONG со- ответственно. Необходимое значение параметра тип_данных мо- жет. быть установлено временно для отдельных команд DEPOSIT и EXAMINE присоединением к коду команды указателя типа. Эти указатели типа являются такими же ключевыми словами, как те, которые используются в команде SET TYPE, а именно: BYTE, WORD и LONG. Ключевое слово LONG следует приме- нять только в тех случаях, когда значение параметра тип-дан- ных, устанавливаемое по умолчанию, было ранее изменено на значение BYTE или WORD. Например, по команде EXAMINE/BYTE SUM печатается содержимое только одного байта памяти с симво- лическим адресом SUM. Поскольку параметр тип-данных не может быть установлен для операций над числами размером двойное длинное слово, та- кие числа необходимо обрабатывать как последовательности из двух длинных слов. 6.1.5. Ввод и вывод целых чисел, размер которых не равен длинному слову Для ввода в машину целых чисел определенного размера и вы- вода их из нее используются команды READ и PRINT соот- ветствующих модификаций: READ-B, READ_W, PRNT-B и PRINT-W. Поскольку количество команд для обработки целых чисел размером длинное слово невелико и необходимость в их использовании возникает редко, то организация ввода и вывода таких чисел здесь не рассматривается. 6.2. Операнды-выражения В предыдущих разделах при описании команд использовались операнды простейших форм: литералы, названия регистров, сим- волические имена переменных (областей памяти). Язык ассемб- лера системы VAX позволяет применять в качестве операндов и более сложные конструкции-выражения (такие операнды на- зывают операндами-выражениями). Операнды-выражения могут быть разделены на следующие типы: относительные, абсолютные и внешние; Относительными являются операнды-выражения, в которых адреса обрабатываемых данных задаются в виде фиксирован- ного смещения относительно начала программы. Независимо от фактического адреса загрузки программы в память относительг ные адреса всегда представляют собой фиксированное смеще.-
Целые числа различных размеров 183 ние местоположения адресуемых данных в памяти относительно адреса начала программы. Операнды, в которых используются символические адреса, всегда являются относительными. Абсолютными являются операнды-выражения, значения кото- рых адресуют конкретные области памяти *>. Они представляют собой константы, формируемые в процессе ассемблирования. Двумя примерами таких операндов-выражений являются число вые константы и разность между относительными адресами, за- даваемыми символическими именами, например А—В. Абсо- лютные операнды-выражения используются редко и поэтому из дальнейшего рассмотрения исключены. Внешние операнды-выражения содержат одно или несколько символических имен, не определенных в «текущем» программ- ном модуле, т. е. модуле, текст которого содержит такие опе- ранды-выражения и ассемблируется в данный момент. Значения, соответствующие этим операндам-выражениям, не могут быть определены транслятором ассемблера; присвоение значений внешним именам, указанным в программах на машинно-ориен- тированном языке, осуществляется служебной программой опе- рационной системы LINK. Операнды могут быть записаны в виде арифметических вы- ражений с определенными ограничениями. Элементами, состав- ляющими такие выражения, могут быть символические имена, числа и знак точка (.) — символическое обозначение счетчика адреса (LC — location counter). Напомним, что во время ассемблирования счетчик адреса (LC) используется аналогично счетчику команд (PC). Он всегда содержит адрес следующего (подлежащего обработке трансля- тором) байта текста программы. Этот адрес обязательно при- надлежит диапазону адресов программы и отсчитывается от ее начала. Транслятор языка ассемблера присваивает счетчику ад- реса нулевое значение в начале обработки (трансляции) текста каждого модуля. При вычислении значения операнда во время трансляции счетчику адреса присваивается значение адреса пер- вого байта операнда. Заметим, что счетчик адреса всегда рас- сматривается как относительный символический операнд, за исключением редко используемого случая применения абсолют- ной адресации. В операндах-выражениях могут использоваться следующие знаки четырех арифметических операций: +, —, * и /. (Пред- полагается, что все арифметические операции в данном случае выполняются над числовыми данными размером длинное слово, поскольку в окончательном виде значение выражения, задаю- о Эти значения представляют собой физические адреса памяти. — Прим, tiepee.
184 Глава 6 щего адрес, представляется как целое число размером длинное слово.) Обратите внимание на то, что описываемые арифмети- ческие операции выполняются во время ассемблирования. Но не думайте, что с помощью указанных операций над элементами операнда-выражения можно изменить содержимое соответствую- щих областей памяти. Содержимое области памяти может быть модифицировано только командами программы во время ее вы- полнения. Следующий пример иллюстрирует выполнение двух различ- ных по назначению арифметических операций. А Пример 6.5. Различие между арифметическими операциями, выполняемыми во время трансляции для формирования адреса операнда и во время выполнения программы для изменения содержимого области памяти MOVL COUNT + 1, RESULT ADDL3 #1, COUNT, RESULT При выполнении первой команды содержимое длинного слова памяти с адресом COUNT+1 пересылается в поле RESULT. При выполнении второй команды содержимое длинного слова с ад- ресом COUNT получает единичное приращение, результат этой операции помещается в область памяти с символическим име- нем RESULT. А Помимо арифметических операций в операндах-выражениях могут быть заданы операции сдвига и логические операции. Зна- ки &,! и \ задают выполнение над группой битов операций И, ИЛИ и ИСКЛЮЧАЮЩЕЕ ИЛИ соответственно. (Логические операции над группами битов рассматриваются в гл. 13.) Знак @, разделяющий два операнда, символизирует сдвиг первого операнда на число бит, задаваемое вторым операндом. Напри- мер, выражение 1@3 определяет сдвиг влево двоичной единицы на три разряда с целью формирования двоичной величины 1000 или восьмерич- ной 8. Если второй операнд подобной операции — отрицательное число, то сдвиг производится вправо с заполнением освобож- дающихся слева разрядов значением бита знака сдвигаемого числа. Все операции двоичной арифметики, используемые в опе- рандах-выражениях, имеют одинаковый приоритет выполнения при вычислении такого выражения. Это правило отличается от правил вычисления арифметических выражений в большинстве языков программирования высокого уровня. Для выделения от- дельных частей операндов-выражений используются, как пока-
Целые числа различных размеров 185 зано ниже, не круглые, а угловые скобки: (SYMBOL 1 + 1) * 17 Наиболее часто применяемые операнды-выражения состоят из символического имени (относительного адреса) и положи- тельного или отрицательного числа (смещения относительно ука- занного адреса, задаваемого константой). Например, для обра- щения к байту памяти, следующему за байтом с символическим адресом (именем) VALUE, которому не присвоено символиче- ское имя, используется выражение VALUE+1. Операнды-выражения, используемые в качестве счетчиков в операндах директив .BLKx, коэффициентов повторения в дирек- тивах .BYTE, .WORD, .LONG, .QUAD и в других (еще не рас- смотренных) директивах, должны содержать символические имена, которые были определены ранее. Это требование играет роль определенного ограничения, смысл которого становится понятным при более детальном ознакомлении с упомянутыми директивами. Заметим, что операнды-выражения, более сложные по кон- струкции, чем те, в которых смещение задается простыми кон- стантами, используются редко. Применять более сложные выра- жения следует крайне осторожно, поскольку это часто сопря- жено с появлением ошибок. Поэтому в дальнейшем изложении сложные выражения для указания адресов используются редко; читателю рекомендуется избегать их употребления. 6.3. Запись констант в системах счисления, отличных от десятичной До сих пор в качестве констант использовались только десятич- ные целые числа. Поскольку при написании программы может потребоваться запись констант в других системах счисления, в языке ассемблера системы VAX предусмотрены соответствую- щие средства. Знак ~ и следующая за ним буква В, О, X или D используются для указания основания системы счисления числа, задаваемого последовательностью цифр, расположенной непо- средственно за указанной буквой. Например, ~В1010 — двоич- ная константа, ~0732 — восьмеричная, ~XF3B — шестнадцате- ричная. Поскольку такие константы могут встретиться в раз- личных частях того или иного выражения, десятичную константу, целесообразно определить явным образом посредством знака и буквы D. Это позволяет указать на использование деся- тичной константы в выражении, записанном в системе счисле- ния, отличной от десятичной. В приведенном ниже примере показаны допустимые способы записи констант и выражений, задающих адреса.
186 Глава 6 Д Пример 6.6. Запись констант в системах счисления, отличных от десятичной: ~В10110011 ~X<F3-1A+~D12) COUNT + ~037 Знак * в сочетании с буквой С используется как символ од- номестной (унарной) операции вычисления обратного кода опе- ранда, записываемого вслед за этой буквой. Например, дирек- тива VALUE: BYTE ~С15 формирует обратный код числа 15 (задаваемого в десятичной системе счисления), имеющий шестнадцатеричное представление FO. В гл. 10 и 12 описывается несколько других унарных опера* ций над константами. 6.4. Оператор присваивания Оператор присваивания позволяет пользоваться так называе- мыми именуемыми константами. Применение таких констант (задаваемых символическими именами) делает программу на языке ассемблера легко читаемой, позволяет, используя выра- жение, вычислить значение константы один раз, а затем поль- зоваться им многократно и, наконец, предоставляет программисту возможность, меняя значения параметра в одной части про- граммы, изменять тем самым значение этого параметра во мно- гих других ее частях. Указанный оператор присваивания имеет следующий формат: символическое „имя = выражение Символическое имя помещается в таблицу символических имен вместе со значением выражения, воспринимаемым как зна- чение, соответствующее этому символическому имени. (Подобно тому как это делается при задании в программе символических адресов.) Выражение не должно содержать неопределенных сим- волических имен. Следующий пример демонстрирует использо- вание операторов присваивания. Д Пример Ъ.Т. Использование операторов присваивания TAB.LEN = 100 TABLE: .BLKQ TAB.LEN VALUE = ~XFEB / ''0713+ 17 MOVL # VALUE, FACTOR
Целые числа различных размеров 187 Символические имена, определенные с помощью подобного оператора присваивания, используются главным образом для присвоения имен константам, формируемым в процессе ассемб- лирования и в ряде случаев вычисляемым как значения неко- торых выражений. Эти константы используются точно так же, как задаваемые символическими именами константы в языках высокого уровня (таких, как язык Паскаль). Рассмотрим, на- пример, программу, в которой несколько различных массивов имеют одинаковое количество элементов. Предположим, что в эту программу требуется внести изменение, заключающееся в увеличении количества элементов массивов на некоторую вели- чину. Если количество элементов каждого массива определяется в программе одной и той же константой, которой присвоено сим- волическое имя, то требуемые изменения можно выполнить, за- менив в программе одну строку — оператор присваивания ука- занному символическому имени нового значения. Если количе- ство элементов массивов задается числовыми константами, то легко допустить ошибку, забыв внести изменения в директиву распределения памяти для какого-либо из массивов. Это в свою очередь приведет к ошибке при выполнении программы, по- скольку при записи в массив, размер которого забыли увели- чить, информация могла выйти за пределы выделенной для него памяти. Значения счетчика адреса можно модифицировать, если его символическое имя использовать в операторе непосредственного присваивания. Например, оператор . = . + 10 выделяет 10 байтов памяти О. Хотя потребность в таком способе выделения памяти возникает редко, он может оказаться полез- ным для определения некоторых типов структур данных. 6.5. Пример программы Приводимая ниже программа (в определенной степени «наду- манная», играющая роль учебного примера) демонстрирует не- которые возможности языка ассемблера из числа рассмотрен- ных в данной главе. Поскольку автор испытывал затруднения в формулировке практической задачи, решение которой потре- бовало бы использования столь многих средств языка ассемб- лера, которые хотелось бы продемонстрировать, предлагаемая программа несколько искусственна по формулировке решаемой задачи. п Увеличивает значение счетчика адреса на 10. — Прим, пер,
188 Глава 6 Д Пример 6.8. • Постановка задачи Исходные данные: три небольших целых числа в диапазоне от —100 до +100. Искомый результат: а) сумма входных чисел, представлен- ных в виде слова; б) произведение квадратов входных чисел, представленных в виде двойного длинного слова; в) результат, полученный в п. б и разделенный на шестнадцатеричное число 6ВЗВ1. Заметим, что результат, полученный в п. б, не может быть выведен на печать с использованием описанных выше команд ввода-вывода. Хотя можно было бы использовать отладчик для отображения этого результата, предлагается это не делать, по- скольку о нормальном выполнении требований п. б можно су- дить по результату, полученному в п. в. Последний можно пред- ставить в виде длинного слова и вывести на печать. • Программа на языке ассемблера ; АРИФМЕТИЧЕСКИЕ ОПЕРАЦИИ НАД ЦЕЛЫМИ ЧИСЛАМИ ; РАЗЛИЧНЫХ РАЗМЕРОВ .PSECT IN-DATA: EXAMPLE, LONG .BLKB 3 ; 3 БАЙТА ПАМЯТИ ; ДЛЯ ИСХОДНЫХ ЧИСЕЛ IN_W: .BLKW 1 ; СЛОВО ПАМЯТИ ; ДЛЯ ВВЕДЕННОГО ;ЧИСЛА SUM_W: .BLKW 1 ; СЛОВО ПАМЯТИ ; ДЛЯ СУММЫ ; ИСХОДНЫХ ; ЧИСЕЛ PROD-Qi .BLKQ 1 ; ДВОЙНОЕ ДЛИННОЕ ; СЛОВО ПАМЯТИ ДЛЯ ; ПРОИЗВЕДЕНИЯ ; КВАДРАТОВ ИСХОДНЫХ ; ЧИСЕЛ QUOTIENT-L: .BLKL 1 ; ДЛИННОЕ СЛОВО ; ПАМЯТИ ДЛЯ ; ЧАСТНОГО ОТДЕЛЕНИЯ ; PROD.Q НА 6ВЗВ1 REMAIN-L: .BLKL 1 ; ДЛИННОЕ СЛОВО ; ПАМЯТИ ДЛЯ ; ОСТАТКА, ; ПОЛУЧЕННОГО ; ПРИ ВЫЧИСЛЕНИИ
Целые числа различных размеров 189 ; QUOTIENT-!. .ENTRY ЕХ_6_8, О INIT-IO CLRW SUM.W READ_B IN-DATA, IN.DATA+1, IN-DATA + 2 ВЫЧИСЛЕНИЕ СУММЫ ИСХОДНЫХ ЧИСЕЛ CVTBW IN-DATA, IN-W ADDW2 IN_W, SUM-W CVTBW IN-DATA + 1, IN-W ADDW2 IN_W. SUM-W CVTBW IN-DATA + 2, IN_W ADDW2 IN_W, SUM_W CVTBW IN-DATA + 2, IN_W ADDW2 IN_W, SUM_W PRINT-W '’’СУММА = ’ SUM_W » ВЫЧИСЛЕНИЕ ПРОИЗВЕДЕНИЯ КВАДРАТОВ ; ИСХОДНЫХ ЧИСЕЛ CVTBL IN-DATA, Rl MULL2 RL Rl CVTBL IN-DATA + 1, R2 MULL2 R2, R2 EMUL Rl, R2, #0, PROD-Q CVTBL IN-DATA + 2, Rl MULL2 Rl, Rl EMUL Rl, PROD-Q, #0, PROD-Q ДЕЛЕНИЕ ПРОИЗВЕДЕНИЯ КВАДРАТОВ ИСХОДНЫХ ; ЧИСЕЛ НА ШЕСТНАДЦАТЕРИЧНОЕ ЧИСЛО 6ВЗВ1 EDIV #"X6B3B1, PROD-Q, - QUOTIENT-L, REMAIN-L PRINT-L PRINT.L SEXIT-S .END "’ЧАСТНОЕ «’, QUOTIENT-L "’ОСТАТОК « REMAIN-L EX_6_8 Заметим, что при вычислении произведения квадратов исход* ных чисел использована команда EMUL. Команда выполняется корректно только потому, что заранее известно следующее: раз- мер квадрата любого исходного числа не превышает длинного слова ((100-100) = 10000 <С 232). Старшие разряды длинного
190 Глава 6 слова с символическим именем PROD_Q всегда очищаются (за- полняются нулевыми битами) при первом выполнении команды EMUL. Результаты выполнения программы примера 6.8 имеют сле- дующий вид: ?75 80 90 СУММА= + 000000000245 ЧАСТНОЕ = + 00000663908 ОСТАТОК = + 00000319964 Фактическая величина произведения квадратов трех входных чисел 75, 80 и 90 составляет 291 600 000000000. Десятичное пред- ставление делителя 439 218; следовательно, частное и остаток имеют корректные значения при заданном формате их представ- ления. Несмотря на свою искусственность, рассмотренная программа демонстрирует использование ряда команд, описанных в данной главе. В последующих главах целые числа, размер которых не равен длинному слову, употребляются по мере необходимости. 6.6. Признаки переполнения и переноса Признаки переполнения и переноса, устанавливаемые в слове состояния процессора, описаны в гл. 3. В данном разделе объяс- няется, при каких ситуациях устанавливаются эти признаки и как они могут быть использованы. Хотя в системе VAX выпол- нение многих команд приводит к изменению состояния индика- торов переполнения и переноса, в данном разделе главное вни- мание уделяется командам выполнения арифметических опе- раций. Признак переполнения используется для указания на то, что результат арифметической операции не умещается в предназна- ченном для него поле. Информация, записанная в это поле, бу- дет представлять собой некорректный результат операции, по- скольку биты данных, выходящие за пределы поля, отбрасы- ваются. Признак переноса используется главным образом при мани- пуляции операндами, представляющими собой величины без знака, в частности при выполнении арифметических операций с повышенной точностью. Например, чтобы сложить содержимое двух двойных длинных слов, необходимо выполнить два после- довательных сложения содержимого длинных слов. Первая из этих операций воспринимает свои операнды как величины без знака. Полученный при ее выполнении бит переноса должен быть учтен во время выполнения второй операции сложения.
Целые числа различных размеров ТЭД Этот процесс подробно описывается в гл. 15. Здесь же рассмат- ривается использование только признака переполнения. Все команды выполнения операций сложения, вычитания, умножения и деления над целыми числами регистрируют факт переполнения. Бит PSW,. являющийся индикатором переполне- ния, равен 1, если результат операции помещается в предназна- ченное для него поле, и равен 0, если этот результат разместить, не удается. Для определения значения признака переполнения в системе VAX предусмотрены две команды условного перехода. Команда BVC (переход при отсутствии переполнения) передает управление по указанному в ней адресу, если признак перепол- нения равен 0, а команда BVS (переход по переполнению)— если признак переполнения равен 1. Если признак переполне- ния равен 0, то управление передается по адресу, указанному в команде BVC (переход при отсутствии переполнения); если же признак переполнения равен 1, то управление передается ш> адресу, указанному в команде BVS (переход по переполнению). Следовательно, при необходимости остановить некоторый про- цесс в программе в случае переполнения нужно вслед за коман- дой, способной вызвать переполнение, разместить команду BVS. Последняя должна содержать в качестве операнда символиче- ский адрес (метку) процедуры обработки данной ошибки (на- пример, процудеры выдачи сообщения о переполнении). Приво- димый ниже фрагмент программы демонстрирует подобное ре- шение.. А Пример 6.9. Обнаружение признака переполнения ADDL2 VALUE, SUM BVS ERROR ERROR: PRINT.L "'ОШИБКА - ПЕРЕПОЛНЕНИЕ ПРИ ВЫЧИСЛЕНИИ "SUM"' После выполнения команды EMUL регистрируется перепол- нение только в тех случаях, когда ее так называемое целое число не равно 0. Это объясняется тем, что поле предназначен-
192 Глава 6 ное для результата выполнения данной команды, всегда доста- точно велико для размещения произведения любых двух целых .чисел размером длинное слово. В результате выполнения команды EDIV, так же как и всех команд DIVxx, переполнение возникает в одной из двух ситуа- ций: частное слишком велико для размещения в предназначен- ном для него поле или делитель равен нулю. Заметим, что команды АСВх также изменяют значение бита признака переполнения. Если значение бита переполнения не проверяется или отменено системное прерывание при переполне- нии, то биты младших разрядов правильного результата исполь- зуются для сравнения с предельным значением параметра цик- ла. Напомним, что системным прерыванием называют обнару- жение аппаратными средствами машины особой ситуации и прекращение выполнения программы (останов). Вместо про- верки значения бита переполнения после выполнения каждой арифметической операции целесообразнее для регистрации пе- реполнения целочисленной арифметики использовать аппарат системного прерывания (trapping), установив в единичное со- стояние соответствующий бит «ловушку» переполнения (trap — бит). Биты-ловушки устанавливаются с помощью отладчика (как описано в гл. 5), а также с помощью команд установки битов, рассматриваемых в гл. 15. В ряде случаев при проверке значения бита переполнения для некоторой операции возникает необходимость в организа- ции условного перехода от той последовательности команд, в ко- торой выполняется данная операция, к некоторой другой. По- скольку в этой книге используется псевдокод и как средство разработки и как способ документирования программ, то и для описания обработки прерываний, возникающих при обнаруже- нии указанных ошибок, воспользуемся ранее не рассматривав- шейся конструкцией псевдокода, а именно оператором EXIT. Бу- дучи расположенным в любом месте программы, этот оператор вызывает выход из внутреннего блока или цикла, в котором он обнаружен. Это свойство оператора EXIT демонстрирует следую- щий пример. Пример 6.10. Оператор псевдокода FOR INDEX : = 1 ТО LENGTH DO * IF условие THEN EXIT END-FOR В этом фрагменте программы оператор EXIT вызывает пере- дачу управления на первый оператор, следующий за оператором конца цикла END-FOR.
Целые числа различных размеров 193 При реализации цикла FOR средствами языка ассемблера оператору EXIT соответствует команда условного перехода на метку, следующую за командами, реализующими оператор кон- ца цикла END-FOR. Если оператор EXIT находится внутри тела цикла WHILE, то управление передается на метку, непосредст- венно следующую за командами, реализующими оператор конца цикла END-DO. Отметим, что наилучший способ решения проблемы перепол- нения, помимо описанных способов контроля его появления, за- ключается в попытке избежать возникновения переполнения за счет предварительного выявления экстремальных значений чис- ловых данных, с тем чтобы предусмотреть возможность устра- нения нежелательных ситуаций до того, как программа начнет выполняться первый раз. Выводы 1. Наряду с командами, обрабатывающими целые числа раз- мером длинное слово, система VAX, располагает командами для работы с целыми числами размером байт, слово и двойное длин- ное слово. 2. Директивы .BLKB, .BLKW и .BLKQ выделяют блоки ячеек памяти размером байт, слово и двойное длинное слово соответ- ственно. 3. При записи в регистры целые числа размером длинное слово размещаются в паре регистров со смежными порядковыми номерами. 4. Директивы .BYTE, .WORD и .QUAD выделяют области па- мяти размером байт, слово и двойное длинное слово соответст- венно и присваивают их содержимому начальные значения, от- личные от нуля. 5. Команды CLRB, CLRW и CLRQ очищают байты, слова и двойные длинные слова памяти соответственно, присваивая их содержимому начальные значения, равные нулю. 6. Команды MOVB, MOVW и MOVQ пересылают целые чис- ла размером байт, слово и двойное длинное слово соответствен- но. Если в командах MOVB и MOVW в качестве операнда-при- емника используются регистры, то содержимое трех или двух байтов старших разрядов регистра сохраняется неизменным. Команды MNEGB, MNEGW и MNEGL пересылают взятые с про- тивоположным знаком целые числа размером байт, слово и длинное слово соответственно. 7. Команды INGx, DECx, ADDx2, ADDx3, SUBx2, SUBx3, DIVx2, DIVx3, MULx2 и MULx3 выполняют арифметические опе- рации над целыми числами размером байт, слово и длинное 7 Зак. 483
194 Глава 6 слово. Использование в позиции х символического имени кода команды буквы В, W или L указывает на то, что размер опе- ранда равен байту, слову или длинному слову соответственно. 8. Команда EMUL перемножает целые числа размером длин- ное слово с записью результата в поле размером двойное длин- ное слово. В команде также предусмотрен операнд для добавле- ния результата предшествующей операции, представленного це- лым числом размером длинное слово. 9. Команда EDIV осуществляет деление целого числа разме- ром двойное длинное слово на целое число размером длинное слово с представлением частного и остатка как целых чисел раз- мером длинное слово. 10. Команды CVTxx выполняют все возможные взаимные преобразования форматов представления целых чисел: BYTE, WORD и LONGWORD. 11. Команды пересылки MOVZxx, заполняя старшие разряды принимающего поля битом 0 (а не битом знака), преобразуют размер целого числа из байта в слово (команда MOVZBW), из байта в длинное слово (команда MOVZBL) и из слова в длин- ное слово (команда MOVZWL). 12. Команды TSTB в TSTW тестируют содержимое областей памяти размером байт и слово соответственно. Команды СМРВ и CMPW выполняют над содержимым соответствующих обла- стей операции сравнения. 13. Команды АСВВ и ACBW выполняют увеличение значе- ния индекса на 1, его сравнение с операндом и передачу управ- ления, используя области памяти размером байт и слово соот- ветственно для размещения индекса. 14. Операнды команд могут быть сложными выражениями, включающими знаки арифметических и логических операций, а также операций сдвига, части выражений, заключенные в угло- вые скобки, символические имена и константы. 15. Выражения могут также использоваться для записи опе- ранда директив .BLKx и коэффициента повторения в директивах .BYTE, .LONG, .WORD и .QUAD; символические имена, исполь- зуемые в этих выражениях, должны быть предварительно опре- делены. 16. Двоичные, восьмеричные, десятичные и шестнадцатерич- ные константы могут быть определены посредством унарных опе- раций ~В, ~O,~D и ~Х соответственно. 17. Обратный код значения, указанного в операнде, может быть сформирован с помощью унарной операции с. 18. Значения, задаваемые с помощью любых операндов-выра- жений (за исключением выражений, содержащих имена регист- ров), могут быть присвоены символическому имени с помощью оператора присваивания.
Целые числа различных размеров 195 19. Большинство команд выполнения арифметических опера- ций устанавливают значение бита признака результата, являю- щегося индикатором переполнения; значение может быть прове- рено с помощью команд условного перехода BVS и BVC. 20. Оператор псевдокода EXIT используется для выхода из цикла при обнаружении ошибки (особой ситуации при выполне- нии программы). Новые команды АСВВ CLRW DECW MNEGL MULB3 ACBW CMPB DIVB2 MNEGW MULW2 ADDB2 CMPW DIVB3 MOVB MULW3 ADDB3 CVTBL DIVW2 MOVQ SUBB2 ADDW2 CVTBW DIVW3 MOVW SUBB3 ADDW3 CVTLB EDIV MOVZBL SUBW2 BVC CVTLW EMUL MOVZBW SUBW3 BVS CVTWB INCB MOVZWL TSTB CLRB CVTWL INCW MULB2 TSTW CLRQ DECB MNEGB Новые директивы .BLKB .BLKW .QUAD .BLKQ .BYTE .WORD Унарные операции для операндов-выражений ~В ~С ~D ЛО ~Х Новые команды ввода-вывода PRINT_B READ.B PRINT.W READ.W Новые термины Константа, формируемая в процессе ассемблирования Операнды-выражения Преобразование с заполнением дополнительных старших разря- дов битом знака Часть выражения операнда (заключаемая в угловые скобки) Преобразование с заполнением дополнительных старших разря- дов нулевым битом. 7*
196 Глава 6 Вопросы и упражнения 1. Как располагаются целые числа размером меньше длин- ного слова в поле, представленном для их размещения? 2. Как располагаются целые числа размером больше длин- ного слова в поле, представленном для их размещения? 3. Что произойдет с содержимым старших разрядов регист- ра при пересылке в него целого числа размером слово с по- мощью команды MOVW? 4. Какой байт содержимого регистра пересылается при ука- зании его в качестве операнда-источника в команде MOVB? 5. Какая проблема возникает при использовании команды АСВВ? 6. В чем различие между выполнением команд CVTBL и MOVZBL? 7. Объясните различие между выполнением следующих двух команд: MOVL IN.DATA-4, OUT SUBL3 #4, IN_DATA, OUT 8. Объясните различие в использовании признаков перепол- нения и переноса. Напишите на языке ассемблера системы VAX структуриро- ванные программы для решения следующих задач. Выполните отладку этих программ. 9. Исходные данные: целое число LENGTH, за которым сле- дует LENGTH целых чисел, значения которых не выходят за пределы диапазона —1000-=—|-1000; LENGTH ^20000. Искомый результат: а) сумма квадратов входных чисел; б) квадрат суммы входных чисел. Замечание. Исходные данные должны быть представлены как целые числа размером длинное слово (случай а)) и двойное длинное слово (случай б)). В качестве счетчика числа повторе- ний выполнения команд тела цикла следует использовать пере- менную целого типа размером слово. Значение бита переполне- ния необходимо проверять после выполнения каждой команды умножения и сложения; при обнаружении переполнения про- грамма должна выводить на печать сообщение об ошибке и пре- кратить свою работу; для этой цели следует использовать опе- ратор EXIT. 10. Исходные данные: список положительных чисел, за кото- рым следует отрицательное число; значения всех положитель- ных чисел заключены в интервале 0 4- 100. Искомый результат: а) сумма квадратов входных чисел, представляемая как целое число размером слово; б) сумма ку-
Целые числа различных размеров 197 бов входных чисел, представляемая как целое число размером двойное длинное слово. Замечание. Исходные данные должны быть представлены как целые числа размером байт каждое. 11. Исходные данные: целое число LENGTH, за которым сле- дует LENGTH целых чисел. LENGTH^ 120; значения входных чисел не выходят за пределы диапазона — 10000 4- 10000. Искомый результат: а) среднее арифметическое отрицатель- ных входных чисел, представляемое как целое число размером слово-, б) среднее арифметическое положительных входных чи- сел, представляемое как целое число размером слово. Замечания: а) исходные данные, имеющие нулевые значения, следует игнорировать; б) счетчики количества положительных и отрицательных вводимых чисел, должны быть представлены пе- ременными целого типа размером слово-, в) переменная, исполь- зуемая в качестве счетчика числа повторений выполнения команд тела цикла, должна быть целого типа размером байт; г) значе- ние бита переполнения должно проверяться после каждой команды умножения и сложения; при обнаружении переполне- ния должно быть выведено на печать сообщение об ошибке, а выполнение программы прекращено; для этой цели следует вос- пользоваться оператором EXIT. 12. Исходные данные: целое число. Искомый результат: максимальное по величине значение ре- зультата возведения исходного числа в такую положительную (случай а)) или отрицательную (случай б)) степень, которая еще не вызывает переполнение при размещении результата в поле размером длинное слово. 13. Исходные данные: число LENGTH, за которым следует LENGTH целых чисел. Искомый результат: числа или сообщения об ошибке, полу- ченные после следующей обработки каждого исходного числа (X): а) если —10 < X < 10, то преобразовать X в целое число раз- мером байт, вычислить и вывести на печать квадрат такого чис- ла, представив его как целое число размером байт; б) если —100 < X —10 или 10 X < 100, то преобразовать X в целое число размером слово, вычислить и вывести на печать квадрат такого числа, представив его как целое число размером слово; в) если 100 X или X —100, то вывести на печать сообще- ние об ошибке. 14. Исходные данные: целое число X, удовлетворяющее усло- вию 10 X 100. Искомый результат: все простые числа, которые больше, чем 10, но меньше или равны X,
198 Глава 6 15. Исходные данные: два целых числа XI и Y1. Искомый результат: значение приводимого ниже выражения, вычисляемого до тех пор, пока очередной его член не вызовет переполнения ((X 13)/(Y12)) + (142 • (X 1*)/(YI3)) + (1526 - (X15)/(Y13)) + + (293 • (X16)/(Y I4)) Пояснение: следует пользоваться парой команд EMUL и EDIV (там, где это возможно), чтобы избежать переполнения. 16. Исходные данные: целое число, значение которого не вы- ходит за пределы диапазона 100 000-i- 1 000 000. Искомый результат: а) четыре целых числа размером слово, каждое из которых содержит один байт исходного числа разме- ром длинное слово и получено преобразованием с заполнением дополнительных старших разрядов битом знака; б) четыре це- лых числа размером слово, каждое из которых содержит один байт исходного числа размером длинное слово и получено пре- образованием с распространением бита 0. 17. Исходные данные: целое число, значение которого не вы- ходит за пределы диапазона 1 000 000 000 4- 2 000 000 000. Искомый результат: столбец чисел размером байт, каждое из которых является очередной десятичной цифрой исходного числа. 18. Исходные данные: четыре целых числа, значения которых не выходят за пределы диапазона 0 4-100. Искомый результат: целое число размером длинное слово, каждый байт которого одно из исходных чисел.
Глава ? Массивы и индексирование Эта глава является введением в технику индексирования — один из методов организации массивов средствами языка ассемблера. Принципы индексирования относительно просты и реализуются в языке ассемблера VAX-11 непосредственно, без использования каких-либо других методов обработки массивов данных. 7.1. Назначение массивов Большинство наиболее интересных и имеющих практическую ценность программ манипулируют массивами данных. Огромное множество задач обработки данных, обычно решаемых на ЭВМ, должны использовать массивы данных. Так, например, сортиров- ка списка чисел, строк символов или записей данных требует использования по крайней мере одного массива. В любой задаче обработки списка связанных между собой данных, доступ к ко- торым осуществляется более одного раза, требуется применение определенной техники манипулирования таким массивом дан- ных. Любой язык программирования высокого уровня общего на- значения (например, Фортран, Бейсик, Кобол, Ада) располагает средствами манипулирования массивами данных. Рассмотрим кратко эти средства языка Паскаль применительно к одномер- ным массивам. Предположим, что программе на языке Паскаль требуется память для размещения списка из 100 целых чисел. Программа сообщает транслятору о необходимости такой памяти с помощью невыполняемого (декларативного) оператора LIST: ARRAY [1..100] OF INTEGER; Во-первых, этот оператор указывает транслятору, что символи- ческое имя LIST — это идентификатор, используемый в качестве базового адреса массива, для размещения которого выделяется данный блок памяти. Во-вторых, от этого же оператора транс- лятор получает информацию о величине допустимого диапазона изменения индексов или адресов (14-100) и размере необходи- мого блока памяти (100 ячеек). В-третьих, ключевое слово
200 Глава 7 INTEGER определяет тип данных, подлежащих записи в ячейки этого блока памяти. Структура массива имеет следующий вид: LISTflJ LIST[2] UST[3] LIST[99J LIST[1OOJ Блок памяти для массива представляет собой непрерывный участок оперативной памяти, т. е. элемент массива LIST[2] рас- полагается непосредственно перед элементом LIST[3], точно так же элемент LIST[49] располагается перед элементом LIST[50] и т. д., благодаря чему выдерживается не только логи- ческая, но и физическая упорядоченность размещения элемен- тов. Внутри программы на языке Паскаль ссылки на элементы массива LIST осуществляются с помощью указателя адреса, со- стоящего из двух частей. Первая часть — идентификатор мас- сива LIST — является неизменной для всех элементов массива. Вторая часть — индекс — может быть константой (числом) це- лого типа, переменной целого типа или любым арифметическим выражением, результат вычисления которого — целое число в диапазоне 1 4- 100. Например, если индекс, именуемый INDEX,—• переменная целого типа, текущее значение которой равно 12, то LIST[10], LIST[INDEX] и LIST[(2-INDEX) — 1] являются именами (указателями адреса) 10-го, 12-го и 23-го элементов массива соответственно. В приводимом ниже фрагменте программы на языке Паскаль осуществляется вычисление суммы элементов массива LIST, при- чем предполагается, что SUM и INDEX определены как симво- лические имена переменных целого типа, а все 100 элементов массива являются целыми числами допустимых значений. Д Пример 7.1. Вычисление суммы элементов массива (программирование на языке Паскаль) SUM : = 0; FOR INDEX : = 1 ТО 100 DO SUM : = SUM + LIST [INDEX];
Массивы и индексирование 201 7.2. Принципы индексирования При программировании на языке ассемблера приходится иметь дело с более низким уровнем организации вычислительной ма- шины, чем при использовании языка Паскаль °. Это требует бо- лее глубокого понимания природы манипулирования массивами данных, поскольку техника адресации к ним на языке ассем- блера близка к ее реализации непосредственно в машинном коде. Пусть переменная В указывает наименьшее значение индекса массива, BASE — адрес начала массива, L — длину (размер) каждого элемента массива. Тогда адрес элемента массива с ин- дексом INDEX определяется выражением BASE + (INDEX - В) • L Полагая элементы массива целыми числами размером длин- ное слово (что типично при программировании на языке Пас- каль системы VAX) и принимая В равным 1, получаем BASE + (INDEX - 1)-4 Графическая интерпретация этого выражения имеет следую- щий вид: <-Базовый аЗрев <- Базовый аЭрес +4 LISTflJ LIST(2] LIST[INDEX] < Базовый аЗрес+ (1NDEX-D-4) LIST[100J <- Базовый адрес +396 В ЭВМ начала 50-х годов использовались весьма громоздкие способы реализации подобной адресации. Адреса операндов команд, манипулирующих элементами массивов, модифицирова- лись во время выполнения программы с помощью других команд, для того чтобы можно было использовать одну и ту же команду *> Большинство современных ЭВМ имеют многоуровневую организацию со следующей типовой иерархией уровней: микропрограммный уровень — тради- ционный машинный уровень — уровень операционной системы — уровень язы- ка ассемблера — уровень проблемно-ориентированных языков, (см., например, Э. Таненбаум. Многоуровневая организация ЭВМ. М, МИР, 1979).— Прим. ред.
202 Глава 7 для обращения к разным элементам массива. Во второй поло- вине 50-х годов был, однако, создан новый, более удобный (с точки зрения программирования) механизм адресации элемен- тов массивов. Если индекс элемента массива не является константой, то адрес, указываемый любой командой, обращавшейся к массиву, не может быть вычислен на этапе трансляции программы (ее преобразования в машинные коды). Эта задача подлежит реше- нию на этапе выполнения программы посредством предназначен- ного для этой цели машинного кода. Чтобы повысить эффектив- ность этого часто используемого кода, было предложено индек- сирование, аппаратно реализующее часть вычислений, необходи- мых для определения адреса элемента массива. В данном слу- чае принцип индексирования предполагает использование аппа- ратных средств для уменьшения времени вычисления адресов элементов массивов, к которым производится обращение. Вы- числение действительного адреса операнда в командах, обра- щающихся к элементам массива, осуществляется на этапе вы- полнения программы путем сложения базового адреса массива со смещением. В машинном коде, реализующем индексирование, должны быть предусмотрены определенные средства запоминания и хра- нения обеих частей адреса: неизменного базового адреса мас- сива и динамически меняющегося значения индекса или смеще- ния. Базовый адрес массива обычно хранится так же, как и при использовании других режимов адресации. Для хранения сме- щения используется регистр. В более ранних ЭВМ, как и во мно- гих современных малых ЭВМ, для индексирования использова- лись специальные регистры, но со времени появления семейства ЭВМ IBM/360 (1963 год) большинство мощных универсальных ЭВМ допускают использование для этой цели любого регистра общего назначения, 7.3. Индексирование в системе VAX Архитектура системы VAX допускает использование для индек- сирования любого регистра общего назначения, за исключением регистра счетчика команд (СК). Хотя почти все типы адресации, применяемые в системе VAX, могут применяться для формирования базового адреса массива, в предшествующих главах рассмотрена только незначительная часть их, что может создать впечатление о применимости для данной цели лишь немногих. В данной главе приемлемой для этого является относительная адресация «смещением к СК»; ис- пользование регистровой адресации или литералов не представ- ляется рациональным.
Массивы и индексирование 203 Многие ЭВМ допускают использование для индексирования лишь некоторого подмножества своих команд или даже только определенных операндов таких команд. Одной из наиболее по- лезных и отличительных особенностей архитектуры системы VAX является ортогональность набора ее команд, означающая, что почти любой тип адресации можно использовать почти для лю- бого операнда практически любой машинной команды. Ограни- чения, выделяемые в данном утверждении словом «почти», озна- чают, что имеются ситуации, при которых определенный тип ад- ресации оказывается не применим. Например, операнд команды BGEQ не может эффективно использоваться для индексирова- ния. В разд. 7.2 утверждается, что индексирование предполагает выполнение аппаратными средствами операции сложения базо- вого адреса массива со смещением, задаваемым индексом эле- мента массива. При реализации индексирования разработчики системы VAX пошли еще дальше: аппаратно осуществляется операция умножения для вычисления требуемого значения сме- щения. Поскольку коэффициент, используемый в этой операции, зависит только от типа размера операнда, который в свою оче- редь может быть определен по коду операции (КОП) машинной команды, то выполнение данной операции не представляется сложным. Тем не менее такое неявное умножение индекса на длину поля операнда редко встречается в других ЭВМ. Благо- даря этому индексирование в языке ассемблера во многом по- добно индексированию в языках высокого уровня. После описа- ния правил синтаксиса индексирования на языке ассемблера (разд. 7.3.1) начатое в данном разделе рассмотрение индексиро- вания продолжается в разд. 7.3.2. 7.3.1. Синтаксис индексирования на языке ассемблера Распределение памяти для массива на языке ассемблера осу- ществляется достаточно просто с помощью директивы .BLKx. Чтобы выделить память для 100 целых чисел приведенного выше фрагмента программы на языке Паскаль, достаточно воспользо- ваться директивой LIST: .BLKL 100 Напомним, что эта директива также присваивает ста резер- вируемым длинным словам памяти нулевые значения. Чтобы показать, что операция индексирования должна ис- пользоваться при вычислении адреса операнда, к символическо- му имени адреса добавляется заключаемое в квадратные скобки имя регистра. Также указывается индекс элемента массива в программах на языке Паскаль. В следующем примере адрес
204 Глава 7 первого операнда вычисляется путем сложения содержимого ре- гистра R6, умноженного на количество байтов, занимаемых эле- ментом массива LIST (четыре), со значением адреса, определяе- мого символическим именем LIST: ADDL2 LIST[R6], SUM Так называемый действительный адрес операнда является его реальным машинным адресом. Для рассматриваемого при- мера вычисление действительного адреса первого операнда ил- люстрирует рис. 7.1. Рис. 7.1. Пример адресации с использованием индексирования. Основное различие в употреблении индекса INDEX массива LIST в программах на языке Паскаль и языке ассемблера за- ключается в том, что в последнем случае значение индекса пе- ред использованием должно быть загружено в регистр, посколь- ку только регистр может указываться в квадратных скобках, следующих за именем массива. Однако это не является недо- статком, так как значение индекса INDEX может оставаться в регистре в течение всего цикла выполнения команд обработки массива LIST. Для того, чтобы в рассматриваемом примере ссылка на массив в программе на языке ассемблера относилась к тому же самому элементу массива, что и при использовании следующего оператора языка Паскаль SUM :== SUM + LIST [INDEX] нижняя граница индекса массива LIST должна быть равной 0. При увеличении значения переменной INDEX на 1 при каждом
Массивы и индексирование 205 выполнении тела цикла суммирования элементов массива транс- лятор языка Паскаль обеспечивает увеличение адреса, задавае- мого выражением LIST[INDEX] на требуемую величину смеще- ния. Архитектура системы VAX также предусматривает решение этой не очень сложной задачи. Контекст операнда, использую- щего индексирование, задаваемый обычно кодом операции команды, указывает размер поля адресуемого операнда. Этот размер определяет коэффициент, на который каждый раз доЛ- жно умножаться содержимое индексного регистра для получе- ния надлежащей величины смещения. Для приводимой выше команды сложения ADDL2 этот коэффициент равен 4, поскольку она имеет дело с 4-байтовыми (длинными) словами. При исполь- зовании команды ADDW2 тот же коэффициент был бы равен 2t В формате машинной команды для индексной адресации байт режима адресации содержит код числа 4 в левом полу- байте и код номера регистра в правом полубайте. Рядом с бай* том режима адресации, определяющим индексный регистр, рас- положен так называемый спецификатор операнда, используемый для вычисления выражения, определяющего базовый адрес мас- сива. Для рассматриваемого примера машинная команда имее^ следующую структуру: 5 4 3 2 1 0 831 AF| 8F Af| 461 СО Байты 1, 2 и 3 задают адрес первого операнда ° — LIST[R6], Значение первого байта (461б) указывает, что регистр R6 ис- пользуется в качестве индексного для модификации адреса, за- даваемого следующим за ним спецификатором (8FAFie). КбД AF16 указывает на использование относительной адресации «сме- щением к СК» с длиной поля представления смещения, равной 1 байт (см. гл. 3), а код 8F16 определяет значение смещения (—ПЗю). Следовательно, адрес операнда определяется сум- мированием содержимого счетчика команд (СК), смещения и умноженного на 4 содержимого регистра R6. Спецификатор вто- рого операнда (83AFie) указывает на использование относитель- ной адресации «смещением к СК» с длиной поля представления смещения, равной 1 байт, причем значение смещения равно 8316(-12510). Следует сделать еще одно замечание относительно синтакси- ческих правил индексирования. Многие программисты, действуя по привычному шаблону, используют единицу в качестве мини* мального значения индекса массива; и действительно ранние версии языка Фортран требовали соблюдения этого условия. Не* *> Перечисление ведется справа налево. — Прим, перев,
206 Глава 7 смотря на то, что язык Паскаль допускает применение и других величин в качестве минимальных значений индекса, многие про- граммисты по-прежнему используют единицу; им это кажется более естественным. Однако с точки зрения механизма индекси- рования принципы манипулирования массивами становятся бо- лее понятными, если полагать всегда, что нижняя граница ин- декса равна нулю. Поскольку адрес области памяти для первого элемента мас- сива определяется только базовым адресом, то содержимое ин- дексного регистра для этого элемента массива должно быть рав- ным нулю. С учетом этого соглашения адрес второго элемента массива равен базовому адресу, к которому добавлен размер об- ласти памяти элемента массива, адрес третьего — базовому ад- ресу, к которому этот размер добавлен два раза, и т. д. Таким образом, всегда предполагается, что для массивов, используе- мых в программах на языке ассемблера, значения индексов на- чинаются с нуля, хотя можно было обобщить подобный подход к индексированию для обеспечения корректной работы и с лю- быми другими минимальными значениями индекса. 7.5.2. Операция индексирования Теперь все подготовлено к написанию на языке ассемблера фраг- мента программы вычисления суммы элементов массива LIST, состоящего из целых чисел размером длинное слово. Д Пример 7.2. Суммирование элементов массива целых чисел размером длинное слово LIST: .BLKL 100 SUM: .LONG 0 CLRL SUM ; ДЛЯ REG: = 0 ДО 99 ВЫПОЛНЯТЬ В ЦИКЛЕ CLRL R6 LOOP: ; ДОБАВЛЕНИЕ LIST[REG] К SUM ADDL2 LIST[R6], SUM AOBLEQ #99, R6, LOOP ; КОНЕЦ ЦИКЛА «ДЛЯ»
Массивы и индексирование 207 Для сложения содержимого группы последовательно распо- ложенных байтов памяти используется следующий фрагмент программы. Л Пример 7.3. Суммирование элементов массива целых чисел размером байт LIST: .BLKB 100 SUM: .BYTE 0 CLRB SUM ; ДЛЯ REG : = 0 ДО 99 ВЫПОЛНЯТЬ В ЦИКЛЕ CLRL R6 LOOP: ; ДОБАВЛЕНИЕ LIST[REG] К SUM ADDB2 LIST[R6], SUM AOBLEQ #99, R6, LOOP ; КОНЕЦ ЦИКЛА «ДЛЯ» > Заметим, что правила синтаксиса языка ассемблера системы VAX, используемые при индексировании, не зависят от размера полей адресуемых операндов. Анализируя контекст выражения, содержащего [R6], вычислительная система устанавливает, что размер операнда равен одному байту, и поэтому в качестве мно- жителя использует величину, равную 1, для получения правиль- ного значения смещения (в этом случае операцию умножения можно просто исключить). Индексирование позволяет существенно расширить диапазон задач, которые можно решать, располагая описанным выше от- носительно небольшим набором команд и типов адресации. Теперь полезно рассмотреть более полный пример. Д Пример 7.4. • Постановка задачи Исходные данные: целое число LENGTH, за которым следует LENGTH целых чисел, LENGTH 100.
208 Глава 7 Искомый результат: целая часть выраженного в процентах отношения количества исходных чисел, больших их среднего арифметического, к общему количеству этих чисел. Воспользуемся некоторыми синтаксическими правилами язы- ка Паскаль по выполнению операций с массивами при описании алгоритма решения задачи на псевдокоде. Псевдокод для за- дачи, рассматриваемой в примере 7.4, относительно прост и не дребует подробных пояснений. • Алгоритм решения задачи на псевдокоде Присвоить начальные (нулевые) значения переменным SUM ц COUNT для суммирования чисел, больших среднего ариф- метического: Ввести LENGTH Установить LIMIT равным LENGTH—1 FOR REG: = 0 ТО LIMIT DO Ввести очередное число в область памяти для элемента массива LISTfREG] Добавить LIST[REG] К SUM END-FOR Вычислить AVERAGE среднее арифметическое FOR REG : = 0 ТО LIMIT DO IF LIST[REG] > AVERAGE THEN увеличить на 1 значение COUNT ENDIF END-FOR Вычислить выраженное в процентах количество чисел больших AVERAGE Вывести на печать результат Конец программы Следует обратить внимание, что в качестве верхней границы диапазона изменения параметра цикла FOR используется пере- менная LIMIT вместо перменной LENGTH. Поскольку операции тела цикла необходимо выполнять LENGTH раз, а начальное значение индекса должно быть равно нулю, то верхняя граница диапазона изменения индекса определяется выражением LENGTH — 1, вычисляемым до выполнения цикла. Заметим также, что в тексте программы на псевдокоде пере- менная REG представляет собой параметр цикла FOR; она же используется и в качестве индекса элементов массива.
Массивы и индексирование 209 • Программа на языке ассемблера ВЫЧИСЛЕНИЕ ВЫРАЖЕННОГО В ПРОЦЕНТАХ ОТНОСИТЕЛЬНОГО КОЛИЧЕСТВА ИСХОДНЫХ ЧИСЕЛ, БОЛЬШИХ ИХ СРЕДНЕГО АРИФМЕТИЧЕСКОГО ИСХОДНЫЕ ДАННЫЕ: ЦЕЛОЕ ЧИСЛО LENGTH, ЗА КОТОРЫМ СЛЕДУЕТ LENGTH ЦЕЛЫХ ЧИСЕЛ LENGTH < 100 ; РЕЗУЛЬТАТ: ВЫРАЖЕННОЕ В ПРОЦЕНТАХ ; ОТНОСИТЕЛЬНОЕ КОЛИЧЕСТВО ЧИСЕЛ, БОЛЬШИХ ИХ СРЕДНЕГО ; АРИФМЕТИЧЕСКОГО .PSECT EXAMPLE, LONG ОБЛАСТИ ПАМЯТИ ДЛЯ SUM: .BLKL 1 ; СУММЫ ВСЕХ ИСХОДНЫХ ЧИСЕЛ LIST: .BLKL 100 ; МАССИВА ВСЕХ ИСХОДНЫХ ; ЧИСЕЛ ;LENGTH: .BLKL AVERAGE: .BLKL 1 ; КОЛИЧЕСТВА ИСХОДНЫХ ЧИСЕЛ 1 ; СРЕДНЕГО АРИФМЕТИЧЕСКОГО ; ИСХОДНЫХ ЧИСЕЛ PERCENT: .BLKL 1 ; ВЫРАЖЕННОЕ В ПРОЦЕНТАХ ; КОЛИЧЕСТВО ЧИСЕЛ, БОЛЬШИХ ; СРЕДНЕГО АРИФМЕТИЧЕСКОГО LIMIT: .BLKL COUNT: .BLKL 1 ; ЗНАЧЕНИЯ LENGTH - 1 1 ; КОЛИЧЕСТВА ИСХОДНЫХ ЧИСЕЛ, ; БОЛЬШИХ СРЕДНЕГО ; АРИФМЕТИЧЕСКОГО .ENTRY INIT-IO CLRL CLRL ЕХ_7_4, 0 SUM COUNT READ_L LENGTH ПРИСВОЕНИЕ ПЕРЕМЕННОЙ LIMIT ЗНАЧЕНИЯ LENGTH - 1 SUBL3 # 1, LENGTH, LIMIT ДЛЯ REG: = 0 ДО LIMIT ВЫПОЛНЯТЬ В ЦИКЛЕ CLRL CMPL BLEQ BRW R6 R6, LIMIT LOOP1 LOOP1_END
210 Глава 7 LOOP1: ; ВВЕСТИ ОЧЕРЕДНОЕ ЧИСЛО В ОБЛАСТЬ ПАМЯТИ ; ЭЛЕМЕНТА МАССИВА LIST [REG] READ-L LIST[R6] ; ДОБАВЛЕНИЕ LIST[REG] К SUM ADDL2 LIST[R6], SUM AOBLEQ LIMIT, R6, LOOP1 ; КОНЕЦ ЦИКЛА «ДЛЯ» ; ВЫЧИСЛЕНИЕ СРЕДНЕГО АРИФМЕТИЧЕСКОГО LOOP1_END DIVL3 LENGTH, SUM, AVERAGE : ДЛЯ REG: = 0 ДО LIMIT ВЫПОЛНЯТЬ В ЦИКЛЕ CLRL R6 CMPL R6, LIMIT BLEQ LOOP2 BRW LOOP2-END LOOP2: • ЕСЛИ LISTfREG] > AVERAGE CMPL LIST[R6], AVERAGE BLEQ ENDIF • TO УВЕЛИЧЕНИЕ HA 1 ; ЗНАЧЕНИЯ COUDT INCL COUNT • КОНЕЦ ОПЕРАЦИИ «ЕСЛИ» ENDIF: AOBLEQ LIMIT, R6, LOOP2 ; КОНЕЦ ЦИКЛА «ДЛЯ» ; ВЫЧИСЛЕНИЕ ВЫРАЖЕННОГО В ПРОЦЕНТАХ ; ОТНОСИТ ЕЛЬНОГО КОЛИЧЕСТВА ЧИСЕЛ, ; БОЛЬШИХ ИХ СРЕДНЕГО АРИФМЕТИЧЕСКОГО
Массивы и индексирование 211 L00P2-END: MULL3 # 100, COUNT, R7 DIVL3 LENGTH, R7, PERCENT PRINT.L ~'КОЛ-ВО ЧИСЕЛ, БОЛЬШИХ СРЕДНЕГО- ; АРИФМЕТИЧЕСКОГО (В %) = ', PERCENT $EXIT.S .END ЕХ.7.4 В этой программе все команды, относящиеся к обработке массива LIST, манипулируют данными размером длинное слово. Поэтому действительный адрес вычисляется путем четырехкрат- ного добавления содержимого индексного регистра к базовому адресу массива. Например, поскольку в команде CMPL LIST[R6], AVERAGE код операции команды CMPL указывает, что сравниваются длинные слова, то действительный адрес первого операнда вы- числяется следующим образом: A(LIST) + (4 • R6) Здесь A(LIST) означает адрес области памяти, именуемой LIST. При использовании команды CMPW вместо команды CMPL адрес вычисляется по формуле A (LIST) 4-(2 - R6) Заметим, что операнды, для обращения к которым исполь- зуется индексная адресация, могут вводиться в память машины и выводиться на печать непосредственно с помощью команд READ-L и PRINT.L. Рассмотрим еще один пример использования индексирования. ГД Пример 7.5 • Постановка задачи Исходные данные: последовательность положительных целых чисел, за которой следует отрицательное целое число. Количе- ство чисел в последовательности меньше 101, а их значения меньше 10 000. Искомый результат: исходные числа, расположенные в по- рядке возрастания их значений (посредством перестановки не- упорядоченных элементов). Простейший вариант подобного алгоритма предполагает вы- полнение следующих операций. Сравниваются первый и второй элементы исходной последовательности. Если они расположены в требуемом порядке, то никаких действий над ними не выпол- няют. В противном случае они меняются местами, Затем первый
212 Глава 7 элемент полученной последовательности, который на самом деле может теперь быть вторым элементом исходной последователь- ности, сравнивается с третьим элементом. И в этом случае при обнаружении неупорядоченности сравниваемых элементов они переставляются местами. Этот процесс продолжается до тех пор, пока не будет произ- ведено сравнение элемента, находящегося в первой позиции, со всеми элементами последовательности. (В действительности ряд элементов исходной последовательности «побывает» на месте первого элемента.) Далее описанная процедура повторяется для второго эле- мента последовательности. После ее завершения второй наи- меньший элемент (из числа оставшихся после нахождения са- мого минимального элемента исходной последовательности) бу- дет помещен во вторую позицию. В результате повторения по- добной процедуры для всех элементов (за исключением послед- него) будет получена последовательность, элементы которой рас- положены в порядке возрастания их значений. Поскольку числа, используемые в примере 7.5, не выходят за пределы диапазона значений, описываемых двумя байтами (словом), для их размещения в памяти используются области размером слово. • Алгоритм решения задачи на псевдокоде Присвоить REG начальное, нулевое значение Ввести первый элемент последовательности в область памяти VALUE WHILE VALUE >=0 DO Переслать VALUE в LISTfREG] Увеличить содержимое REG на единичное приращение Ввести очередной элемент в область памяти VALUE END-DO Присвоить LENGTH значение REG Присвоить TOP_LIMIT значение LENGTH — 2 Присвоить ВОТ-LIMIT значение LENGTH — 1 FOR TOP-REG := О ТО TOP-LIMIT DO Присвоить BOT_START значение TOP-REG + 1 FOR ВОТ-REG :=BOT_START TO BOT.LIMIT DO IF LIST[TOP_REG] > LIST[BOT_REG] THEN переставить элементы местами ENDIF END-FOR
Массивы и индексирование 213 END-FOR FOR REG:=0 ТО BOT_LIMIT DO Вывести на печать LISTfREG] END-FOR Конец программы Отметим, что данный алгоритм упорядочивания элементов по- следовательности методом их последовательных перестановок, именуемый сокращенно «сортировка обменом», не является са- мым быстрым. Хотя существуют значительно более быстрые ал- горитмы упорядочения, выбор рассмотренного алгоритма в дан- ном случае объясняется его простотой. Приведем текст программы на языке ассемблера, реализую* щей данный алгоритм. • Программа на языке ассемблера ; ПРИМЕНЕНИЕ АЛГОРИТМА СОРТИРОВКИ ОБМЕНОМ ; ДЛЯ РАЗМЕЩЕНИЯ ИСХОДНЫХ ЧИСЕЛ В ПОРЯДКЕ ВОЗРАСТАНИЯ ; ИХ ЗНАЧЕНИЙ ; ИСХОДНЫЕ ДАННЫЕ: ПОСЛЕДОВАТЕЛЬНОСТЬ ; ПОЛОЖИТЕЛЬНЫХ ЦЕЛЫХ ЧИСЕЛ, ЗА КОТОРОЙ СЛЕДУЕТ ОТРИЦАТЕЛЬНОЕ ЧИСЛО. ; КОЛИЧЕСТВО ПОЛОЖИТЕЛЬНЫХ ; ЧИСЕЛ МЕНЬШЕ 101 КАЖДОЕ ИЗ НИХ ПО ВЕЛИЧИНЕ МЕНЬШЕ 10000 ; РЕЗУЛЬТАТ: ИСХОДНЫЕ ЧИСЛА, РАСПОЛОЖЕННЫЕ ; В ПОРЯДКЕ ВОЗРАСТАНИЯ ИХ ЗНАЧЕНИЙ ; ПОСРЕДСТВОМ АЛГОРИТМА ; СОРТИРОВКИ ОБМЕНОМ .PSECT EXAMPLE, LONG ; ОБЛАСТИ ПАМЯТИ ДЛЯ VALUE: .BLKW 1 ;БУФЕРА ДЛЯ ВХОДНЫХ . LIST: .BLKW 100 ; И ВЫХОДНЫХ ДАННЫХ ; МАССИВА ИСХОДНЫХ ЧИСЕЛ LENGTH: .BLKL 1 ; КОЛИЧЕСТВА ЭЛЕМЕНТОВ В МАССИВЕ BOT_START: .BLKL 1 ; ПАРАМЕТРА ВНУТРЕННЕГО ЦИКЛА TOP_LIMIT: .BLKL 1 ; ВЕРХНЕЙ ГРАНИЦЫ ПАРАМЕТРА BOT-LIMIT: .BLKL 1 ; ВНЕШНЕГО ЦИКЛА ; ВЕРХНЕЙ ГРАНИЦЫ .ENTRY EX_7_5, 0 ; ПАРАМЕТРА ВНУТРЕННЕГО ЦИКЛА
214 Глава 7 INIT-IO ; ПРИСВОЕНИЕ REG НАЧАЛЬНОГО, НУЛЕВОГО ЗНАЧЕНИЯ И ВВОД ; ПЕРВОГО ЧИСЛА CLRL R6 READ-W VALUE ; ПОКА VALUE > О ВЫПОЛНЯТЬ В ЦИКЛЕ LOOP: TSTW VALUE BLSS END_DO ! ; ПЕРЕСЫЛКА ЗНАЧЕНИЯ VALUE В LIST ; И ЕДИНИЧНОЕ ПРИРАЩЕНИЕ СОДЕРЖИМОГО REG MOVW VALUE, LIST[R6] INCL R6 READ-W VALUE BRW LOOP ; КОНЕЦ ЦИКЛА «ПОКА» ; ПЕРЕСЫЛКА ЗНАЧЕНИЯ REG В LENGTH END-DO: MOVL R6, LENGTH •ПРИСВОЕНИЕ TOP-LIMIT ЗНАЧЕНИЯ LENGTH-2, ; A BOT-LIMIT ЗНАЧЕНИЯ LENGTH-1 SUBL3 #2, LENGTH, TOP-LIMIT SUBL3 # 1, LENGTH, BOT-LIMIT • ДЛЯ TOP-REG :=0 ДО TOP-LIMIT ВЫПОЛНЯТЬ В ЦИКЛЕ CLRL R0 CMPL R6, TOP-LIMIT BLEQ OUTER-LOOP BRW O_LOOP_END OUTER-LOOP: •ПРИСВОЕНИЕ BOT-START ЗНАЧЕНИЯ TOP-REG4-1 ADDL3 #1, R6, BOT-START ; ДЛЯ BOT_REG:= BOT-START ДО BOT-LIMIT
Массивы и индексирование 215 ; ВЫПОЛНЯТЬ В ЦИКЛЕ MOVL ВОТ-START, R7 INNER-LOOP: ЕСЛИ LIST[TOP_REG] > LIST[BOT_REG] CMPW BLEQ LIST[R6], LIST[R7] ENDIF » MOVW MOVW MOVW TO ПЕРЕСТАВИТЬ ЭЛЕМЕНТЫ МАССИВА МЕСТАМИ LIST[R6], R8 LIST[R7], LIST[R6] R8, LIST[R7] КОНЕЦ ОПЕРАЦИИ «ЕСЛИ» ENDIF: AOBLEQ BOT.LIMIT, R7, INNER-LOOP • КОНЕЦ ЦИКЛА «ДЛЯ ВОТ-REG» I_LOOP_END: AOBLEQ TOP-LIMIT, R6, OUTER-LOOP ; КОНЕЦ ЦИКЛА «ДЛЯ TOP-REG» O_LOOP-END: PRINT-L "'УПОРЯДОЧЕННЫЙ СПИСОК ИСХОДНЫХ ЧИСЕЛ' ДЛЯ REG := О ДО BOT.LIMIT ВЫПОЛНЯТЬ В ЦИКЛЕ CLRL CMPL BLEQ BRW P-LOOP: R6 R6, BOT.LIMIT P-LOOP P-LOOP-END PRINT-W ', LIST[R6J AOBLEQ BOT.LIMIT, R6, P-LOOP ; КОНЕЦ ЦИКЛА «ДЛЯ REG» P-LOOP-END: $EXIT_S .END EX-7-5
216 Глава 7 1А. Команда INDEX Команда INDEX обеспечивает проверку индекса, используемого для обращения к элементам одномерного или многомерного мас- сива, на принадлежность допустимому диапазону значений. Эта команда имеет следующий формат: INDEX индекс .элемента, нижняя .граница, верхняя.граница, размер.элемента, начальное .значение, выходной.индекс Операнд индекс-элемента представляет собой индекс адресуе- мого элемента массива при условии, что нижней границей диапа- зона значений индекса является 0. Операнды нижняя.граница и верхняя-граница используются для задания соответствующих значений, и если данный индекс элемента выходит за границы задаваемого ими диапазона, то возникает прерывание, именуе- мое «выход индекса за пределы допустимого диапазона значе- ний». Все операнды команды INDEX представляют собой дан- ные размером длинное слово. Операнд начальное-значение ис- пользуется при работе с массивами, для которых нижняя гра- ница диапазона изменения индекса не равна нулю, а также для обращения к элементам многомерных массивов. Для одномерных массивов с нижней границей, равной нулю, в качестве этого опе- ранда используется литерал 0. В качестве операнда, именуемого выходной-индекс, обычно используется имя регистра, в который команда INDEX помещает индекс адресуемого элемента масси- ва. После выполнения этой операции можно адресоваться к та- кому элементу массива. Действия, выполняемые по команде INDEX, могут быть описаны следующим псевдокодом: Присвоить выходному индексу значение выражения (на- чальное_значение + индекс_элемента) • размер_элемента IF индекс_элемента < нижняя.граница OR индекс.элемента > верхняя граница THEN прерывание из-за выхода индекса за диапазон допустимых значений ENDIF Конец выполнения команды Если операнд начальное-значение равен нулю, то первая строка псевдокода будет иметь вид: Присвоить выходному индексу значение индекс-элемента • раз- мер-элемента Основным назначением команды INDEX является проверка принадлежности текущего значения индекса диапазону допусти- мых значений. Поскольку обычно индексирование используется
Массивы и индексирование 217 для адресации элементов одномерных массивов, содержащих данные стандартных (для системы VAX) типов, программисту не нужно заботиться о выполнении операции умножения длины элемента массива на значение его индекса, поскольку выполне- ние такого умножения не явно подразумевается при реализации индексирования. При выполнении команды INDEX в слове состояния процес- сора присваивается значение 1 биту N, если выходной индекс — отрицательная величина, и биту Z, если выходной индекс равен нулю. В следующем примере выводится на печать значение элемен- та массива длинных слов LIST. Диапазон значений индекса эле- ментов массива равен 0 4- 99. Индекс элемента, значение кото- рого подлежит выводу на печать, находится в поле COUNT. Пе- ред использованием содержимое этого поля проверяется: INDEX COUNT, #0, #99, #1, #0, R5 PRINT.L '''COUNT ELEMENT OF LIST = ', LIST[R5] Если нижняя граница диапазона допустимых значений индекса не равна 0, то для правильного выполнения команды INDEX не- обходимо соответствующим образом задать операнд начальное- значение. Поскольку выходной-индекс определяется как началь- ное значение + индекс элемента, то для получения корректного результата операнд начальное-значение может быть взят рав- ным отрицательному значению операнда нижняя~граница. Пред- положим, например, что имеется массив длинных слов, индексы элементов которых не выходят за пределы диапазона —5 4- +5. Чтобы использовать команду INDEX для проверки принадлеж- ности индекса указанному диапазону значений, содержимое ин- дексного регистра необходимо определить следующим заданием значений операндов этой команды: INDEX SUBSCRIPT, #-5, #5, #1, #5, R5 В данном случае содержимому регистра R5 присваивается зна- чение выражения начальное-значение + индекс-элемента или 5 + SUBSCRIPT. Если значение SUBSCRIPT равно —2, то в регистр R5 загружается 5 — 2 = 3. Подобное решение является корректным: элемент с индексом —2 — четвертый по порядку элемент массива, адресуемый содержимым индексного регистра, равным 3. 7.5 Матрицы Матрицы — двухмерные массивы — являются широко используе- мой формой представления данных. Они применяются для хра- нения информации в виде таблиц или, например, как компактная
218 Глава 7 форма записи коэффициентов систем линейных алгебраических уравнений. Несмотря на то что в представлении пользователя матрицы всегда имеют два измерения, в памяти машины они за- писываются в виде одномерных массивов. Для реализации та- кого хранения матриц используется процедура преобразования ссылок на элементы матрицы в смещение адреса элемента одно- мерного массива. Хотя в некоторых языках программирования используются другие способы размещения и адресации элементов матриц в па- мяти, здесь рассматривается только наиболее распространенный способ, именуемый последовательным, размещением строк. Это означает, что элементы матрицы располагаются в памяти после- довательно строка за строкой. Например, матрица 2 1 6 3 4 2 0 5 3 записывается в память последовательно строка за строкой, как показано на рис, 7.2, 2 1 6 3 4 2 О 5 3 Рис. 7.2. В большинстве языков программирования ссылка на элемент матрицы представляет собой имя матрицы и два индекса: номер строки и номер столбца. Для преобразования таких ссылок к виду, определяющему положение элемента матрицы как элемен- та эквивалентного одномерного массива, может использоваться следующая функция / (номер.строки, номер .столбца) = (номер.строки • количество, столбцов + номер.столбца) • размер.элемента Эта функция легко реализуется на языке ассемблера, по- скольку механизм индексирования системы VAX предусматри- вает умножение индекса на размер элемента. Следующий при- мер поясняет, как осуществляется доступ к элементам матрицы. Матрица целых чисел, каждое из которых размером слово, со- стоит из 50 строк и 10 столбцов.
Массивы и индексирование 219 Д Пример 7.6. Обращение к элементам матрицы MAXROWS = 50 MAXCOLS = 10 MAT: .BLKW MAXROWS * MAXCOLS ROW: .BLKL 1 COL: .BLKL 1 MULL3 ROW, # MAXCOLS, R5 ADDL2 COL, R5 PRINT.W "'ЭЛЕМЕНТ MATP. C HOM. — СТР. И СТОЛБЦА - ROW И COL = ', MAT[R5] Если необходимо проверить принадлежность индексов допу- стимым диапазонам значений, то можно использовать команду INDEX для вычисления адресов элементов матрицы. Поскольку команды INDEX выполняют подобную проверку только для од- ного индекса, то при работе с матрицами этой командой необхо- димо воспользоваться дважды. Первая команда INDEX прове- ряет номер строки и умножает его на количество столбцов, ис- пользуя последнее в качестве значения операнда размер-элемен- ia. Вторая команда INDEX проверяет номер столбца и добав- ляет его к результату, полученному при выполнении первой команды. Такая процедура показана в приводимом ниже при- мере, повторяющем предыдущий пример с добавлением опера- ций контроля принадлежности индексов диапазонам допустимых значений. А Пример 7.7. Использование команды INDEX при обраще- нии к элементам матрицы MAXROWS = 50 MAXCOLS = 10 MAT: .BLKW MAXROWS * MAXCOLS ROW: •BLKL 1 COL: .BLKL 1 INDEX ROW, #0, # (MAXROWS - I>, — # MAXCOLS, #0, R5 INDEX COL, #0, #(MAXCOLS- 1>,#I,— R5, R5
220 Глава 7 PRINT. W "'ЭЛЕМЕНТ МАТР. С НОМ. СТР.— И СТОЛБЦА ROW — И COL = ', MAT[R5] Отметим, что использование команды INDEX не упрощает вычисления адреса элемента матрицы и, более того, даже де- лает их менее эффективными. Достоинством же этой команды является возможность контроля принадлежности индекса диапа- зону допустимых значений. Выводы 1. Одномерный массив представляет собой основную струк- туру данных большинства выполняемых на ЭВМ программ. 2. Адресация элементов массива предполагает добавление смещения к базовому адресу массива. В большинстве ЭВМ эта процедура реализуется путем помещения значения смещения в регистр. На этапе выполнения программы содержимое этого ре- гистра добавляется к базовому адресу массива. Это осуществля- ется аппаратно и называется индексированием или модифика- цией адреса индексным регистром. 3. Сочетание возможностей транслятора языка ассемблера и аппаратных средств системы VAX обеспечивает сравнительно простую реализацию индексирования. 4. На языке ассемблера индексный регистр указывается в операнде команды путем его записи в квадратных скобках сразу вслед за базовым адресом операнда. Тип данных, определяемый кодом операции команды, указывает размер операнда в байтах. Это значение умножается на содержимое регистра, а результат добавляется к базовому адресу для получения адреса операнда в памяти. 5. При организации обращения к массивам в программах на языке ассемблера с использованием индексного регистра обычно принято считать, что отсчет значений начинается с нуля. В цик- лах, осуществляющих обработку массивов, один и тот же ре- гистр используется как для размещения параметра (переменной) цикла FOR, так и индексной части адреса, модифицирующей ба- зовый адрес массива. 6. Команда INDEX представляет собой удобное средство вы- числения адресов элементов массива в тех случаях, когда тре- буется проверка принадлежности индексов элементов диапазону допустимых значений. Новые термины Базовый адрес массива Индексирование Матрицы
Массивы и индексирование 221 Проверка принадлежности индекса диапазону допустимых зна- чений Вопросы и упражнения 1. Какой вид имеет выражение для определения адреса эле- мента одномерного массива с индексом INDEX, минимальное значение которого (индекса) равно 5, а размер элемента мас- сива равен 8? 2. Объясните, как выполняется процесс индексирования на уровне машинных команд. 3. Предположим, что 23Bi6 — адрес, соответствующий симво- лическому имени LIST, а содержимое регистра R8 равно 5. Чему равны адреса чисел, пересылаемых в поле RESULT при выпол- нении следующих команд: a) MOVB LIST [R8], RESULT б) MOVL LIST [R8], RESULT в) MOVW LIST [R8], RESULT Напишите на языке ассемблера программы для решения сле- дующих задач. Выполните отладку этих программ. 4. Исходные данные*, целое число LENGTH, за которым сле- дует LENGTH целых чисел; LENGTH<101. Искомый результат: последовательность исходных чисел, в которой все отрицательные числа предшествуют всем положи- тельным числам при условии, что в остальном порядок следова- ния чисел остается неизменным. 5. Исходные данные: последовательность отрицательных це- лых чисел, количество которых меньше 100, за которой следует положительное целое число. Искомый результат: выраженное в процентах относительное количество исходных чисел, значения которых заключены в ин- тервале ±5 от среднего арифметического. Например, если вели- чина среднего арифметического равна 243, то величины границ указанного интервала равны 237 и 248 соответственно. 6. Исходные данные: последовательность целых положитель- ных чисел, расположенных в порядке возрастания их значений, за которыми следует отрицательное число и еще пять положи- тельных целых чисел. Общее количество положительных чисел меньше чем 100. Искомый результат: последовательность исходных чисел, в которую включены дополнительные пять чисел таким образом, что сохраняется первоначальная упорядоченность. 7. Исходные данные: последовательность целых положитель- ных чисел, каждое из которых меньше 1000, за которыми сле- дует отрицательное число.
222 Глава 7 Искомый результат: последовательность исходных чисел, из которой изъяты повторяющиеся числа (т. е. каждое уникальное значение представлено одним числом). Общее количество иско- мых чисел меньше чем 100). Замечание. Для решения этой задачи следует использовать массив данных, размер каждого элемента которого равен одному слову. 8. Исходные данные: целое число LENGTH, за которым сле- дует LENGTH целых чисел, значения которых не выходят за пре- делы диапазона —100 4- +100; LENGTH<100. Искомый результат: а) последовательность положительных чисел, имеющихся среди исходных чисел; б) последовательность отрицательных чисел, имеющихся среди исходных чисел. Замечание: а) числа, равные нулю, следует игнорировать; б) необходимо сформировать два новых массива (один с поло- жительными числами, другой с отрицательными), прежде чем выводить результат решения. (Это упражнение на формирова- ние новых массивов, а не вывод массивов на печать); в) для ре- шения задачи следует использовать представление каждого чис- ла одним байтом, 9. Исходные данные1, целое число, за которым расположены две последовательности целых чисел, размером LENGTH каж- дое; обе последовательности упорядочены по возрастанию содер- жащихся в них чисел; LENGTHclOl. Искомый результат: последовательность всех исходных чисел, расположенных в порядке возрастания их значений. Замечание. Не следует просто поместить все исходные числа в один массив, а затем выполнить его сортировку. Необходимо из двух исходных последовательностей сформулировать два от- дельных массива. Каждое исходное число должно помещаться в требуемую позицию результирующего упорядоченного массива с помощью только одной операции пересылки. 10. Исходные данные: последовательность целых чисел, вели- чины которых заключены в диапазоне 0 + 99, за которыми сле- дует число —1. Искомый результат: выводимое на печать распределение входных чисел по интервалам значений, вычисляемое путем под- счета количества чисел, значения которых принадлежат диапа- зонам О-т-9, Ю-т-19, ..., 904-99. Замечание. Используйте преобразованные соответствующим образом входные числа в качестве значений индекса массива, каждый элемент которого — один из десяти счетчиков количе- ства исходных чисел соответствующего диапазона значений. 11. Исходные данные: число LENGTH, за которым следует LENGTH целых чисел, где LENGTH<101,
Массивы и индексирование 223 Искомый результат: исходные данные, размещенные в обрат- ном порядке. Замечание. Необходимо поместить все исходные числа в мас- сив, реорганизовать его, расположив элементы массива в поряд- ке, обратном исходному, а затем вывести значения элементов массива на печать начиная с первого элемента. 12. Исходные данные: последовательность положительных це- лых чисел, количество которых менее 51; за ними следует чис- ло — 1. Искомый результат: исходные числа, расположенные в поряд- ке убывания их значений (посредством алгоритма сортировки по методу «пузырька»). Замечание. Алгоритм сортировки по методу «пузырька» подо- бен алгоритму сортировки по методу перестановок. Отличие со- стоит в том, что всегда сравниваются только смежные элементы последовательности. Последовательность операции сравнения имеет следующий вид: первый элемент со вторым, второй с третьим,..., предпоследний с последним, первый со вторым, вто- рой с третьим....предшествующий предпоследнему с предпо- следним, первый со вторым, ... 13. Исходные данные: число LENGTH, за которым следует LENGTHC101 целых чисел; Искомый результат: а)' количество исходных чисел, значения которых превышают среднее арифметическое нечетных по поряд- ку исходных чисел (первого, третьего и т. д.); б) количество исходных чисел, значения которых меньше среднего арифмети- ческого четных по порядку исходных чисел (второго, четвертого нт. д.). 14. Исходные данные: два целых числа ROW и COL, за ко- торыми следует (ROW-COL) целых чисел размером длинное слово каждое; за одну процедуру ввода загружается одно число. Значения ROW и COL не больше 6. Искомый результат: а) сумма элементов каждой строки ис- ходной матрицы; б) сумма элементов, расположенных на обеих диагоналях исходной матрицы. Замечание. Команду INDEX следует использовать при всех обращениях к матрице, за исключением ввода ее исходных дан- ных. 15. Исходные данные: те же, что и в п. 14, за исключением того, что вместо одной вводятся две матрицы одинакового раз- мера. Искомый результат: Матрица, представляющая собой сумму двух исходных матриц, выводимая на печать по одному элемен- ту в каждой строке. Замечание. При составлении программы не следует использо- вать команду INDEX.
Глава 8 Косвенная адресация В языках ассемблера почти всегда допускается, а зачастую не- обходимо применение косвенной адресации. В современных язы- ках высокого уровня, таких, как ПЛ/1, Си, Паскаль и Ада, пре- дусмотрена возможность применения такой адресации. В дан- ной главе излагаются принципы косвенной адресации, способы ее реализации в системе VAX и некоторые примеры использо- вания. Несмотря на то что здесь описываются не только принципы этой новой эффективной адресации, но и правила ее задания на языке ассемблера, только содержание глав 9 и 10 раскрывает основные области ее применения. Поэтому в данной главе в про- цессе описания новых способов формирования выражений для задания адресов неоднократно подчеркивается, что эффектив- ность их применения раскрывается содержанием последующих глав. 8.1. Принципы косвенной адресации Рассмотрим противозаконную ситуацию обращения к услугам профессионального арзониста (человека, осуществляющего за деньги незаконный поджог недвижимого имущества). Поскольку для такой личности это является рутинной работой, она выпол- няется с высокой степенью профессионализма. Однако поиск ра- боты для арзониста является серьезной проблемой. Амораль- ность, неэтичность и нелегальность этой профессии очевидна. Поэтому потенциальные наниматели арзонистов на работу стре- мятся всячески избежать огласки своих отношений с лицами этой профессии. Один подобный наниматель решил проблему установления контакта с арзонистом следующим образом. Подозревая, что его телефон прослушивается, он желал избежать не только передачи арзонисту по телефону адреса строения, подлежащего поджогу, но и вообще личной телефонной связи с ним. Поэтому он решил позвонить арзонисту и сообщить ему адрес телефонной будки, где на сотой странице телефонной книги он написал адрес строе- ния. При условии осведомленности арзониста о подобной техни- ке коммуникации с нанимателем, проблемы последнего решают-
Косвенная адресация 225 ся полностью: невозможно установить взаимосвязь телефонных разговоров нанимателя с возникновением пожара. В этой выдуманной истории наниматель изобрел принцип косвенной адресации. Вместо передачи адреса строения, которое нужно поджечь, он передал адрес места, в котором может быть найден адрес упомянутого строения. Подобный принцип косвен- ной адресации в течение десятилетий находит свое воплощение в архитектуре ЭВМ. Основное назначение косвенной адресаций — повышение гиб- кости способов адресации операндов, что особенно важно при манипулировании с данными сложной структуры. Принцип кос- венной адресации является основополагающим также и при пе- редаче параметров подпрограммам во многих языках програм- мирования. В этих языках косвенная адресация означает, что операнд указывает местоположение адреса, по которому нахо- дятся данные, участвующие в операции, а не местоположение этих данных. 8.2. Регистровая косвенная адресация В языке ассемблера системы VAX возможны различные спо- собы реализации косвенной адресации, простейший из которых получил название регистровой косвенной адресации. В этом слу- чае адрес операнда, к которому производится обращение, поме- щается в регистр. В команде на языке ассемблера имя такого регистра помещается в круглые скобки, что является указанием на размещение в регистре не самого операнда, а только его адре- са. Например, команда MOVL VALUE, (R3) пересылает содер- жимое длинного слова памяти, имеющего символический адрес VALUE, в область памяти, адрес которой находится в регистре R3. Рассмотрим следующий пример. Д Пример 8.1. Регистровая косвенная адресация 0000 1735: R3 0000 19FB: 1735 MOVL R3, R4 MOVL (R3), R5 В этом примере действительным адресом первого операнда первой команды MOVL является регистр R3, тогда как действи- тельным адресом первого операнда второй команды MOVL яв- ляется содержимое регистра R3. В результате выполнения этих команд в регистр R4 загружается шестнадцатеричное число 1735, а в регистр R5 — содержимое длинного слова, находящегося по адресу 1735, т. е. шестнадцатеричное число 19FB. Рис. 8.1 демон- стрирует выполнение этих операций, В соответствии с форматом 8 Зак. 483
226 Глава 8 машинных команд для задания регистровой косвенной адреса- ции используется один байт, содержимым левого полубайта ко- торого является число 6, а правого — номер регистра. Например, для приведенной ниже команды языка ассемблера соответствую- щий ей код машинной команды имеет следующий вид: MOVL (R5)t R6 2. 1 О 156 |б5 |ро Ясно, что при использовании регистровой косвенной адреса- ции необходимы средства для загрузки в регистры корректных Рис. 8.1. Сопоставление косвенной и простой регистровой адресации. (имеющих смысл) адресов. При программировании на языке ассемблера системы VAX для этой цели применяются команды пересылки адресов. Команда MOVAx пересылает адрес своего первого операнда по адресу, аадаваемому вторым операндом. В мнемоническом обозначении кода операции этой команды х— условное обозна- чение одной из следующих букв: В (байт), W (слово), L (длин- ное слово), Q (двойное длинное слово). Например, команда MOVAB VALUE, R5 загружает адрес целого числа размером байт с Символическим именем VALUE в регистр R5.
Косвенная адресация 227 В определенном смысле команда MOVx представляет собой версию команды MOVAx, использующую косвенную адресацию. Команда MOVAx пересылает значение символического имени, представляющее собой адрес, в то время как команда MOVx пе- ресылает содержимое ячейки памяти, указываемой символиче- ской формой задания адреса этой ячейки. Поскольку данные, пересылаемые по команде MOVAx, все- гда представляют собой адрес, то размер последнего во всех случаях равен длинному слову. Причем это положение справед- ливо независимо от типа данных, указываемых в первом операн- де, или вида последней буквы (условное обозначение х) мнемо- нического обозначения кода операции команды. Так как пересылка адреса регистра не имеет смысла, то ука- зание имени регистра в первом операнде команды MOVAx недо- пустимо. То же самое относится и к коротким по длине лите- ралам. Эти команды обычно используют в качестве первого операн- да символические имена. Поскольку размер поля данных, зада- ваемых этим операндом, не играет никакой роли при выполне- нии команды, то может показаться странным наличие четырех различных команд MOVAx. Хотя в большинстве случаев размер поля данных действительно не играет никакой роли, использова- ние различных модификаций команды MOVAx облегчает чтение программы. В разд. 8.3 описаны два новых способа адресации, для которых в отдельных случаях должны использоваться над- лежащие версии команды MOVAx. На машинном языке операнды команды MOVAx записывают- ся и воспринимаются точно так же, как и операнды других ко- манд, таких, как команда MOVx. Во время выполнения програм- мы, однако, вместо того чтобы использовать вычисленный адрес операнда для обращения к данным, находящимся в памяти, ЭВМ использует этот адрес как данные, над которыми следует выполнить операцию пересылки. Косвенная адресация часто применяется как альтернатива индексирования. Приводимый ниже пример демонстрирует ис- пользование косвенной адресации при вводе последовательности чисел размером длинное слово каждое и формирование из них массива. Д Пример 8.2. Регистровая косвенная адресация LENGTH: .BLKL 1 LIST: .BLKL 100 COUNT: .BLKL 1 8*
228 Глава 8 PRINT-L ~'ДЛИНА ПОСЛЕДОВАТЕЛЬНОСТИ LENGTH: READ__L LENGTH MOVAL LIST, R5 ; ДЛЯ COUNT := 1 ДО LENGTH ВЫПОЛНЯТЬ В ЦИКЛЕ MOVL #1, COUNT CMPL COUNT, LENGTH BLEQ LOOP BRW OUT-LOOP LOOP: * ПОМЕСТИТЬ СЛЕДУЮЩЕЕ ЧИСЛО В МАССИВ LIST PRINT_L "'СЛЕДУЮЩЕЕ ЧИСЛО' READ_L (R5) ADDL2 # 4, R5 AOBLEQ LENGTH, COUNT, LOOP ; КОНЕЦ ЦИКЛА «ДЛЯ» OUT_LOOP: He рекомендуется использовать косвенную адресацию в тех случаях, когда возможно применение индексирования. Вариант программы с использованием индексирования значительно легче «читается» и не требует явного указания операций приращения адреса. При написании программы легко ошибиться при записи этих операций или вообще забыть о них. Однако не следует ду- мать, что косвенная адресация является бесполезной. В своих более сложных формах косвенная адресация обеспечивает боль- шую гибкость обращения к данным, чем индексирование, особен- но в тех случаях, когда необходимо манипулировать с адресами данных сложной структуры. 8.3. Косвенная адресация с автоматическим увеличением или уменьшением адреса » Определенным неудобством использования регистровой косвен- ной адресации является необходимость программирования опе- раций увеличения содержимого регистра, в котором находится *> Эти разновидности регистровой косвенной адресации в дальнейшем сокращенно называются адресациями с автоувеличением и автоуменьшением адреса. — Прим, ред.
Косвенная адресация 229 адрес при каждом выполнении тела цикла. Адресация с автома- тическим увеличением (автоувеличением) адреса позволяет устранить этот недостаток. Для задания такого режима адреса- ции необходимо поместить знак «+» после операнда, уже запи- санного в виде, соответствующем регистровой косвенной адре- сации: MOVL VALUE, (R5) + Отличие между регистровой косвенной адресацией и адреса- цией с автоувеличением адреса заключается в том, что во вто- ром случае содержимое указанного регистра автоматически по- лучает соответствующее приращение после того, как фактиче- ский адрес операнда уже был определен и использован. Следо- вательно, величина, добавляемая к содержимому регистра, за- висит от размера поля адресуемых данных или контекста коман- ды (указания типа обрабатываемых данных в коде операции команды). В приведенной выше команде содержимое регистра R5 сначала используется в качестве адреса операнда, а затем к нему добавляется число 4, поскольку контекст команды указы- вает, что размер операнда равен длинному слову. Если вместо мнемонического кода операции MOVL воспользоваться кодом MOVB, то содержимое регистра R5 увеличивается на 1, а не на 4. Используя в примере 8.2 адресацию с автоувеличением адре- са, две команды READ.L VALUE, (R5) ADDL2 # 4, R5 можно заменить одной READ.L VALUE, (R5) + Возможность автоматического увеличения значения адреса повышает практическую ценность косвенной адресации. В этом случае она проще в использовании и при этом уменьшается ве- роятность ошибок. Однако применение косвенной адресации даже для обработки простых массивов делает программу менее наглядной, хуже читаемой. Чтобы в этом случае определить, ка- кие объекты адресуются операндом с автоувеличением адреса, следует в предшествующем тексте искать операцию присвоения содержимому регистра исходного значения. Тем не менее адре- сация с автоувеличением адреса является существенно эффек- тивнее индексирования благодаря исключительной простоте вы- числения действительного адреса операнда. Иногда представляется более удобным осуществлять про- смотр и обработку элементов массива не в прямом, а обратном направлении. С целью обеспечения такой возможности в архи*
230 Глава 8 тектуре системы VAX предусмотрен режим адресации с автома- тическим уменьшением (автоуменьшением) адреса, при котором осуществляется «отрицательное приращение» содержимого реги- стра, используемого для реализации косвенной адресации. Для задания режима косвенной адресации с автоуменьшением адре- са необходимо указать знак «—» перед заключенным в круглые скобки именем регистра. Величина, вычитаемая из содержимого регистра, определяется размером поля данных, адресуемых опе- рандом. Если, согласно коду операции команды, размер операн- да равен слову, то вычитается число 2, если размер операн- да равен длинному слову, вычитается число 4 и так далее. Следующий пример должен дать ясное представление об осо- бенностях использования адресации с автоувеличением и авто- уменьшением адреса. С целью сравнения рассмотренных ранее различных способов адресации к элементам массивов приводят- ся три варианта вычисления суммы 100 элементов массива це- лых чисел размером слово каждое: использование адресаций с автоувеличением и автоуменьшением адреса, а также адресации с помощью индексного регистра. Д Пример 8.3. Адресация с автоувеличением и автоуменьше- нием адреса SUM: .BLKW 1 LIST: .BLKW 100 COUNT: .BLKL 1 ВЫЧИСЛЕНИЕ СУММЫ С ИСПОЛЬЗОВАНИЕМ АВТОУВЕЛИЧЕНИЯ АДРЕСА MOVAW LIST, R5 CLRW SUM ; ДЛЯ COUNT := 1 ДО 100 ВЫПОЛНЯТЬ В ЦИКЛЕ MOVL # 1, COUNT LOOP1: ; ДОБАВЛЕНИЕ К СУММЕ ОЧЕРЕДНОГО ЭЛЕМЕНТА ADDL2 (R5)+, SUM AOBLEQ # 100, COUNT, LOOP1 ; КОНЕЦ ЦИКЛА «ДЛЯ»
Косвенная адресация 231 ; ВЫЧИСЛЕНИЕ СУММЫ С ИСПОЛЬЗОВАНИЕМ ; АВТОУМЕНЬШЕНИЯ АДРЕСА ’ MOVAW LIST+ 200, R5 CLRW SUM ; ДЛЯ COUNT := 1 ДО 100 ВЫПОЛНЯТЬ В ЦИКЛЕ MOVL # 1, COUNT LOOP2: ; ДОБАВЛЕНИЕ К СУММЕ ОЧЕРЕДНОГО ЭЛЕМЕНТА ADDW2 — (R5), SUM AOBLEQ # 100, COUNT, LOOP2 ; КОНЕЦ ЦИКЛА «ДЛЯ» ; ВЫЧИСЛЕНИЕ СУММЫ С ИСПОЛЬЗОВАНИЕМ ; ИНДЕКСИРОВАНИЯ ’ CLRW SUM • ДЛЯ REG:=0 ДО 99 ВЫПОЛНЯТЬ В ЦИКЛЕ CLRL R5 LOOP3: • ДОБАВЛЕНИЕ К СУММЕ ОЧЕРЕДНОГО ЭЛЕМЕНТА ADDW2 LIST[R5], SUM AOBLEQ #99, R5, LOOP3 ; КОНЕЦ ЦИКЛА «ДЛЯ» Даже поверхностное сравнение этих фрагментов программ по- казывает, что индексирование требует на одну команду меньше, чем адресация с автоувеличением или автоуменьшением адреса. Кроме того, при использовании индексирования текст програм- мы более читаем. В случае применения адресации с автоумень- шением адреса важно правильно задать начальное значение со- держимому регистра. Несоблюдение этого требования (выполне- ние которого не столь элементарно, как при других сравнивав-
232 Глава 8 мых способах адресации) является источником ошибок. С этой точки зрения адресация с автоуменьшением адреса наиболее подвержена ошибкам программирования. В примере 8.3 выпол- нение указанного требования не вызывает затруднений, посколь- ку размер массива — константа. Но если бы размер был задан некоторой переменной программы, например LENGTH, то значе- ние переменной следовало бы умножить на 2 и только после этого добавить к содержимому регистра. Выполнение этих опе- раций потребовало бы дополнительной команды. Решая даже эту небольшую проблему, допустить ошибку довольно легко. Заметим, что в случае индексирования обычно регистр ис- пользуется и как счетчик повторения операций тела цикла FOR («ДЛЯ»), и как индексный регистр, т. е. так же, как и при про- граммировании на языке высокого уровня. Однако при исполь- зовании регистровой косвенной адресации, а также адресации с автоувеличением или автоуменьшением адреса счетчик цикла не имеет никакого отношения к адресации элементов массива. При использовании адресации с автоувеличением адреса опе- ранд команды в машинном коде занимает единственный байт, левая половина которого содержит двоичный код числа 8, а пра- вая — номер регистра. В случае адресации с автоуменьшением адреса левая половина этого байта содержит двоичный код чис- ла 7, а правая — по-прежнему номер регистра. Ниже приводится запись команды на языке ассемблера и ее представление в ма- шинном коде: MOVL -(R5H <RB) + 2 10 86175 |РО Все три рассмотренные режимы косвенной адресации могут использовать индексирование. Вычисление действительных адре- сов операндов в этих случаях требует пояснений. Если при адресации одновременно используется индексирова- ние и регистровая косвенная адресация, базовый адрес вычис- ляется так, как будто бы индексирование отсутствует. После этого реализуется индексирование по той же схеме, что и в слу- чае использования базового адреса при относительной адресации «смещением к СК». Рассмотрим, например, следующий фраг- мент программы. А Пример 8.4. Совместное использование регистровой кос- венной адресации и индексирования LIST: .WORD 7, 9, 11, 12 A: .BLKW 1 В: .BLKW 1
Косвенная адресация 233 С: .BLKW 1 MOVL #2, Rl MOVAL LIST, R5 MOVW (R5)[R1], A MOVW - (R5)[R1], В MOVW (R5)4-[R1],C В предположении, что символическому имени LIST соответствует, адрес 542, имеем LISTC03 0007 :542' LISTC1] 0009 :544 LISTC21 000В :54В LISTC33 ОООС 5 548 При выполнении фрагмента программы примера 8.4 первые две команды загрузят числа 2 и 542 в регистры R1 и R5 соответ- ственно. Действительным адресом первого операнда третьей команды (MOVW (R5) [Rl], А) является число 546 или сумма значений базового адреса (542) и содержимого регистра R1 (2), умножен- ного на размер элемента массива (2). Поэтому в область А пе- ресылается десятичное число 11. Действительным адресом первого операнда четвертой коман- ды (MOVW — (R5) [Rl], В) является число 544 или сумма значе- ний базового адреса (540 = 542 — 2) и содержимого регистра R1 (2), умноженного на размер элемента массива (2). Поэтому в поле В пересылается десятичное число 9. Действительный адрес первого операнда пятой и последней команды нашего примера (MOVW (R5)+ [Rl], С) равен дей- ствительному адресу четвертой команды (544), поскольку адрес вычисляется до того, как выполняется операция его автоматиче- ского увеличения. Следовательно, пятая команда пересылает де- сятичное число 9 в область С, а затем добавляет число 2 к со- держимому регистра R5. Рис. 8.2 должен помочь читателю понять, как вычисляется адрес операнда в случае, когда одновременно применяется кос- венная адресация и индексирование.
234 Глава 8 В машинном коде команды для операнда, одновременно ис- пользующего индексирование и регистровую косвенную адреса- цию, адресацию с автоувеличением или автоуменьшением адре- са, предоставляются два байта. Первый из них — это так назы- ваемый индексный байт с двоичным кодом числа 4 в левой поло- вине байта и номером регистра в правой половине байта. Второй байт выполняет функции указателя косвенной адресации; его формат описан ранее. Действительный адрес, определяемый выражением (R2)[R3) = 524,0 + (3 -4)= 524,ь + С16 = 530,6 Рис. 8.2. Объединение регистровой косвенной адресации и индексирования. Для иллюстрации изложенного ниже приводится запись ко- манды на языке ассемблера и соответствующее ей представле- ние в машинном коде: SUBLZ (R51+CR3J » Г<6 3 2 10 56185 [ 43 I С2~1 Косвенную и индексную адресацию можно использовать сов- местно для организации обработки массивов. Это демонстрирует следующий пример: Л Пример 8.5. Обработка массива с использованием индек- сирования и регистровой косвенной адресации LIST: .BLKL 100 SUM: .LONG 0
Косвенная адресация 235 MOVAL LIST, R5 ; СУММИРОВАНИЕ ПЕРВЫХ 50 ЭЛЕМЕНТОВ МАССИВА «LIST» ; ДЛЯ REG:=0 ДО 49 ВЫПОЛНЯТЬ В ЦИКЛЕ CLRL R6 LOOP: • ДОБАВЛЕНИЕ К СУММЕ ОЧЕРЕДНОГО ЭЛЕМЕНТА ’ ADDL2 (R5) [R6], SUM AOBLEQ #49, R6, LOOP • КОНЕЦ ЦИКЛА «ДЛЯ» * Вспомните сделанное ранее замечание, что выбор того или иного варианта кода операции MOVAx в некоторых случаях имеет определенное значение (т. е. модификации кода операции не эквивалентны). При использовании адресации с автоувеличе- нием или автоуменьшением адреса, не задающих в явном виде размер операнда, транслятор языка ассемблера должен быть способен решить, какую величину следует добавлять или вычи- тать из содержимого регистра. Поскольку размер операнда мо- жет быть определен по виду кода операции, в командах пересыл- ки адреса MOVAX предусмотрены различные модификации кода операции. Например, при выполнении команды MOVAW — (R5), ADDR из содержимого регистра R5 перед его использованием вычи- тается число 2. В заключение отметим, что при совместном использовании адресации с автоувеличением или автоуменьшением адреса и индексирования в команде должны указываться два различных регистра: один для индексирования, а другой для автоувелнче- ния или автоуменьшения адреса. В случае регистровой косвенной адресации с индексированием для обеих целей может использо- ваться один и тот же регистр. 8.4. Режим адресации с использованием смещения Часто обрабатываемые данные представляются в виде наборов записей, называемых файлами. Обычно каждая запись — это со- вокупность данных различных типов: целых чисел, числовых данных других типов, символьной информации. Поскольку до сих пор использовались только целые числа, то в рассматривае- мом ниже примере обработки записей числовая информация представлена целыми числами.
236 Глава 8 Предположим, что информация о каждом студенте некото- рого учебного заведения представлена записью, включающей но- мер полиса социального обеспечения, номер курса, возраст, ин- тегральную оценку успеваемости (GPA, Grade Point Average), задаваемую целым числом в диапазоне 04-400 (соответствую- щим истинному значению GPA, выраженному в относительных величинах от 0.0 до 4.0), и пол (кодируемый числом 0 для жен- щин и 1 для мужчин). Структура записи имеет следующий вид: 3 2 10 Номер полиса GPA Age Class Sex :RECORD :RECORD+4 •.RECORD+ 8 Для обращения к различным частям этой структуры удобно воспользоваться относительной адресацией «смещением к РОН» (РОН— Регистр Общего Назначения). Использующий такую адресацию операнд записывается в виде смещения (числовой ве- личины или выражения) и следующего за ним в круглых скоб- ках номера регистра общего назначения. Такая форма записи Операнда подобна случаю регистровой косвенной адресации с добавлением к операнду в качестве префикса смещения. Дей- ствительный адрес операнда вычисляется путем добавления ве- личины смещения к адресу, содержащемуся в указанном ре- гистре. Использование адресации «смещением к РОН» обеспечивает удобный доступ к любому полю записи о студенте. Если, напри- мер, адрес записи находится в регистре R5, а программа содер- жит операторы присваивания SSN_O = 0 CLASS-0 = 4 AGE_O = 5 GPA_O = 6 SEX_O = 8 то содержимое отдельных полей записи можно переслать в дру- гие ячейки памяти с помощью следующих команд: MOVL SSN_O(R5), SOC.NUM MOVB CLASS-0(R5), CLASS MOVB AGE_O (R5), AGE MOVW GPA_O(R5), GPA MOVB SEX_O (R5), SEX
Косвенная адресация 237 Смещение в командах на языке ассемблера системы VAX мо- жет быть задано в виде любого допустимого для операндов команд выражения. Если величина смещения известна, то транс- лятор языка ассемблера выбирает минимальный размер поля (длинное слово, слово или байт), достаточный для его размеще- ния. Если величина смещения неизвестна, поскольку смещение задано с помощью относительных величин или определяется в Рис. 8.3. Относительная адресация «смещением к РОН». тексте исходной программы в дальнейшем, транслятор резерви- рует область памяти размером слово для размещения величины смещения. Программа LINK выдает диагностическое сообщение об ошибке, если поле, предоставляемое для смещения, недоста* точно для его размещения. В разд. 8.5 объясняется, как задавать размер поля представления смещения при использовании относи- тельной адресации «смещением к СК» и «смещением к РОН», Заметим, что адресация «смещением к СК» представляет со- бой особый случай адресации «смещением к РОН», при которой в качестве базового адреса используется содержимое регистра, выполняющего функции счетчика команд (СК)0. Операнд-выра- жение, не содержащий заключенное в круглые скобки имя ре- Именуемая сокращенно здесь и в дальнейшем адресация «смещением к РОН» является разновидностью косвенной адресации. — Прим. pedt
238 Глава 8 гистра, указывает, что для определения базового адреса исполь- зуется счетчик команд, причем величину смещения относительно этого базового адреса должен вычислять транслятор ассемблера. Операнд-выражение, содержащий заключенное в круглые скобки имя регистра, указывает, что величина смещения определена программистом, а для вычисления действительного адреса опе- ранда в качестве базового адреса используется содержимое этого регистра, а не счетчика команд. Машинный код операнда, использующего адресацию «смеще- нием к РОН», имеет длину от 2 до 5 байт. Формат этого кода полностью подобен формату машинного кода операнда, исполь- зующего адресацию «смещением к СК»; отличие только в содер- жимом байта кода режима адресации: вместо счетчика команд здесь указывается номер соответствующего регистра общего на- значения. Левая половина байта 1 (второй байт справа) машин- ного кода команды содержит информацию о размере поля пред- ставления смещения: А — для поля размером байт, С — разме- ром слово, и Е — размером длинное слово. Правая половина этого байта содержит номер регистра с базовым адресом. В по- следующих байтах поля операнда размещается значение смеще- ния. Ниже приводятся команда на языке ассемблера и соответ- ствующий ей машинный код: ADDB2 42(R3H R4 3 2 10 54|2Д Аз|80~ 8.5. Относительная косвенная адресация Такая адресация используется в том случае, когда необходимо запоминать и использовать не один, а несколько адресов (по- следовательность адресов). При этом режиме адресации область памяти, содержащая адрес операнда, представляет собой длин- ное слово, адресуемое посредством относительной адресации «смещением к СК». Для указания на использование относитель- ной косвенной адресации операнду должен предшествовать знак «@». Адресация реализуется точно так же, как и при использо- вании в качестве операнда имени регистра. В приводимом ниже примере последние две команды пересылают содержимое одного и того же слова памяти: MOVAW MOVAW MOVW MOVW KOUNT, R1 KOUNT, ADDR_KOUNT (Rl), RESULT @ADDR_KOUNT, RESULT
Косвенная адресация 239 Формат машинного кода для операндов, использующих отно- сительную косвенную адресацию, предусматривает запись в ле- вой половине байта режима адресации двоичного кода шестна- дцатеричной цифры F — при размещении смещения в поле раз- мером длинное слово, цифры D — при использовании поля раз- мером слово, цифры В — для поля размером байт. Отметим, что указанные одноразрядные шестнадцатеричные числа на единицу больше соответствующих чисел Е, С и А, используемых для ука- зания размера поля представления смещения при относительной адресации «смещением к РОН». Поскольку при относительной косвенной адресации предполагается использование счетчика ко- манд, номер соответствующего регистра указывается в регистро- вой части байта режима адресации так же, как и в случае отно- сительной адресации «смещением к СК». Машинный код последней команды приведенной выше груп- пы команд (MOVW @ADDR_KOUNT, RESULT) имеет следу- ющий вид: 4 3 2 10 42 Af|3B BF |Р0 Байт 1 указывает, что используются регистр F, выполняющий функции счетчика команд, и смещение, помещенное в поле раз- мером байт (согласно указателю В), для вычисления адреса поля, содержащего адрес операнда. Байт 2 указывает, что сме- щение равно ЗВ16 (в шестнадцатеричной системе счисления) или 59ю (в десятичной). Байты 3 и 4 описывают операнд, использую- щий относительную адресацию «смещением к СК», причем в поле размером байт указано смещение, равное 42i6 или 66ю. Оба смещения, заданные в команде, могут быть использованы только в сочетании с адресами команды и данных. Директива .ADDRESS, как показано ниже, используется для выделения области памяти размером длинное слово и помеще- ния в нее адреса, указанного в операнде директивы: ADDR_ KOUNT: . ADDRE S S KOUNT Операндом директивы .ADDRESS может быть также список вы- ражений, задающих несколько адресов, как показано в приве- денном ниже примере: ADDR_TABLE: .ADDRESS SUM, KOUNT, RESULT В приводимом ниже фрагменте программы (пример 8.6) от- носительная косвенная адресация используется для вывода на печать значений элементов массива, а массив состоит из 50 эле- ментов, каждый из которых занимает в памяти один байт,
240 Глава 8 А Пример 8.6. Использование относительной косвенной адресации LIST: .BLKB 50 ADDR_LIST: .ADDRESS LIST COUNT: .BLKW 1 ; ДЛЯ COUNT := 1 ДО 50 ВЫПОЛНЯТЬ В ЦИКЛЕ MOVW # 1, COUNT LOOP: PRINT_W '“'СЛЕДУЮЩЕЕ ЗНАЧЕНИЕ', @ADDR_LIST ; ПРИРАЩЕНИЕ АДРЕСА INCL ADDR_LIST ACBW #50, # 1, COUNT, LOOP ; КОНЕЦ ЦИКЛА «ДЛЯ» Заметим, что к содержимому поля ADDR-LIST необходимо добавлять единицу при каждом очередном выполнении тела цик- ла. Поскольку это и не удобно, и является источником возмож- ных ошибок, применение относительной косвенной адресации следует ограничить теми ситуациями, когда не может быть ис- пользовано индексирование. В приводимом ниже примере по- следняя команда пересылки пересылает содержимое третьего слова блока ячеек памяти TABLE в поле RESULT. А Пример 8.7. Совместное использование относительной косвенной адресации и индексирования TABLE: .BLKL 100 ADDR.TAB: .ADDRESS TABLE MOVL # 2, R5 MOVL @ADDR_TAB[R5], RESULT
Косвенная адресация 241 Рис. 8.4. Совместное использование относительной косвоенной адресации и ин дексирования. В данном случае в относительную косвенную адресацию включено индексирование только для иллюстрации такой воз- можности: для адресации элементов таблицы TABLE можно ограничиться только индексированием. Относительная косвенная адресация и индексирование ис- пользуются совместно при передаче адреса массива подпрограм- ме в качестве параметра. В этом случае, как показано в гл. 10, любое обращение к массиву должно осуществляться с использо- ванием косвенной адресации. В тех случаях, когда в качестве параметров используется несколько массивов, для обращения к элементам которых необходимо индексирование, то для хране-
242 Гллм, 8 ния адресов массивов используются не регистры, а области па- мяти. На рис. 8.4 показано, как вычисляется адрес операнда, со- вместно использующего относительную косвенную адресацию и индексирование. 8.6. Двухуровневая косвенная адресация Косвенная адресация, о которой шла речь до сих пор, может быть названа одноуровневой. Иногда оказывается целесообраз- ным использование двухуровневой косвенной адресации. Напри- мер, при манипуляции адресами, передаваемыми подпрограммам в качестве параметров. При двухуровневой косвенной адресации поле операнда команды содержит адрес поля, в котором нахо- дится адрес, указывающий местоположение значения операнда (т. е. данных, непосредственно участвующих в операции, задавае- мой командой). Два рассмотренных выше режима косвенной адресации — с автоувеличением адреса и «смещением к РОН» — могут быть модифицированы для задания двухуровневых косвенных адре- сов. С этой целью перед соответствующими операндами необхо- димо указать знак «@», например @(R5) + и @42 (R6). Такие формы адресации называются косвенной с автоувеличением ад- реса и косвенной «смещением к РОН» соответственно 1}. Если величина смещения равна нулю, то для задания двойной кос- венной адресации операнду, первоначально использующему ре- гистровую косвенную адресацию, достаточно указать перед ним знак «@». Такую форму адресации можно назвать регистровой двойной косвенной адресацией. Таким образом, имеется три фор- мы задания двухуровневой (двойной) косвенной адресации. Действительный адрес операнда, использующего двойную косвенную адресацию с автоувеличением адреса, вычисляется следующим образом. Содержимое указанного регистра исполь- зуется для адресации к области памяти размером длинное слово. Содержимое этой области используется как адрес памяти, это и есть действительный адрес операнда; после определения этого адреса содержимое указанного регистра увеличивается на 4. По- ясним сказанное следующим примером: 0000 18F0 :R5 0000 5163 :358 0000 0358 :18F0 MOVW @(R5) + , RESULT ° Следует обратить внимание, что адресации с автоувеличением адреса и «смещением к РОН» являются разновидностями косвенной адресации, а по- этому полными названиями указанных форм адресации являются следующие: двойная косвенная с автоувеличением адреса и двойная косвенная «смеще- нием к РОН», — Прим. ред.
Косвенная адресация 243 Рис. 8.5. Двойная косвенная адресация с автоувеличением адреса. F Действительный адрес первого операнда этой команды MOVW представляет собой содержимое ячейки памяти, адресуе- мой содержимым регистра R5, т. е. этот адрес равен 358 — числу, находящемуся по адресу 18F0, указанному в качестве содержи- мого регистра R5. Данная команда пересылает шестнадцатерич- ное число 5163 в область памяти RESULT, а затем добавляет 4
244 Глава 8 к содержимому регистра R5. Отметим, что к содержимому ре- гистра R5 было бы добавлено число 2 в случае обычной адреса- ции с автоувеличением адреса, поскольку регистр R5 тогда адре- совался бы к слову памяти. В случае косвенной адресации с автоувеличением адреса регистр R5 всегда адресуется к длинно- му слову памяти. Следовательно в данном случае должно до- бавляться число 4. Рис. 8.6. Использование регистра для указания местоположения адреса. Рис. 8.5 показывает, как выполняется команда MOVW при использовании косвенной адресации с автоувеличением адреса. Чтобы лучше понять двухуровневую косвенную адресацию, рас- смотрим следующий пример. Рис. 8.6 демонстрирует ситуацию, которая имеет место перед выполнением фрагмента программы, приведенного в следующем примере. Д Пример 8.8. Использование регистровой двойной косвенной адресации ; ПЕРЕСЫЛКА 48 БАЙТОВ ДАННЫХ ИЗ ОБЛАСТИ, ; АДРЕС КОТОРОЙ УКАЗЫВАЕТСЯ РЕГИСТРОМ R7, В ОБЛАСТЬ, . АДРЕС КОТОРОЙ УКАЗЫВАЕТСЯ РЕГИСТРОМ R8 i
Косвенная адресация 245 COUNT: .BLKW 1 ; ДЛЯ COUNT := 1 ДО 6 ВЫПОЛНЯТЬ В ЦИКЛЕ MOVW # 1, COUNT LOOP: • ПЕРЕСЫЛКА ДВОЙНОГО ДЛИННОГО СЛОВА И ПЕРЕСЫЛКА ; УКАЗАТЕЛЕЙ MOVW @ (R7), @ (R8) ADDL2 # 8, (R7) ADDL2 # 8, (R8) ACBW #6, # 1, COUNT, LOOP • КОНЕЦ ЦИКЛА «ДЛЯ» S Проанализируем использование косвенной адресации «сме- щением к РОН» на следующем примере: 0000 0420 :R5 0000 15FB :244 0000 7F00 :420 0000 0244 :424 0015 0000 :428 0000 0015 :42С MOVL @4(R5), RESULT В результате выполнения команды пересылки в поле RESULT записывается число 0000 15FB, размер которого равен длинному слову. Действительный адрес местоположения этого числа, рав- ный 244, вычисляется путем добавления числа 4 к содержимому регистра R5 (4 + 420 = 424). По адресу 424 находится число 0000 0244, используемое как адрес длинного слова памяти, со- держащего число 0000 15FB. Все три формы двухуровневой (двойной) косвенной адреса- ции допускают использование индексирования. В дальнейшем сочетание индексирования с указанными формами адресации ис- пользуется в тех случаях, когда действительный адрес операнда должен быть адресом элемента массива. Следующий пример де- монстрирует сочетание индексирования с регистровой двойной косвенной адресацией.
246 Глава 8 Д Пример 8.9. Совместное использование регистровой двойной косвенной адресации и индексирования 0000 0850 :R5 0000 0007 :758 0300 0005 :75С 0000 0010 :760 0000 0003 :764 0000 0006 :768 0000 0758 :850 CLRL SUM ; ДЛЯ REG:=0 ДО 4 ВЫПОЛНЯТЬ В ЦИКЛЕ CLRL R6 LOOP: ; ДОБАВЛЕНИЕ ОЧЕРЕДНОГО ЭЛЕМЕНТА ; В НАКОПИТЕЛЬ ИСКОМОЙ СУММЫ ADDL2, @(R5)[R6], SUM AOBLEQ #4, R6, LOOP ; КОНЕЦ ЦИКЛА «ДЛЯ» В результате выполнения цикла содержимое области памяти SUM становится равным 7 + 5+16+ 3 + 6 = 37 (десятичное число). В этом цикле регистр R5 содержит в начале число 850 и сохраняет свое содержимое неизменным до конца цикла, что же касается содержимого регистра R6, то при каждом выпол- нении тела цикла оно получает приращение, равное 1, тем са- мым изменяясь от 0 до 4; в результате таких изменений действи- тельными адресами первого операнда команды сложения после- довательно являются следующие числа: 758, 75С, 760, 764 и 768. Необходимость указания в операнде двух регистров при со- вместном использовании адресации с автоувеличением адреса и индексирования сохраняется также и при двойной косвенной адресации.
Косвенная адресация 247 8.7. Управление размером смещения Для обоих типов смещения, используемого механизмом адреса- ции системы VAX (при относительной адресации «смещением к СК» и «смещением к РОН»), размер поля представления смеще- ния выбирается транслятором языка ассемблера. Если для операнда используется адресация «смещением к СК» и при этом известно численное значение выражения, представ- ляющего этот операнд, то транслятор языка ассемблера выби- рает минимально допустимый размер поля представления сме- щения (длинное слово, слово или байт). Если выражение, пред- ставляющее операнд, содержит символические имена, которые определяются в исходной программе только в дальнейшем или задается их числовое значение в другой программной секции, определяемой директивой .PSECT, то транслятор считает, что значение выражения неизвестно и по умолчанию выделяет для его размещения поле размером длинное слово. Размер данного поля, принимаемый по умолчанию, может быть изменен с по- мощью директивы .DEFAULT, имеющей следующую обобщен- ную форму: .DEFAULT DISPLACEMENT, ключевое _слов о где в качестве ключевого слова могут указываться служебные слова LONG, WORD или BYTE. Язык ассемблера системы VAX позволяет программисту ука- зывать в программе требуемый размер поля представления сме- щения для любого или для всех операндов, использующих отно- сительную адресацию «смещением к СК». Для этого необходимо перед операндом поместить знак унарной (одноместной) опера- ции задания размера поля смещения. Знак подобной операции формируется из указания основания — буквы В, W или L — и следующего за ней знака «~»: В~ — для смещения размером байт, W~ — размером слово и L" — размером длинное слово. При использовании адресации «смещением к СК» рекомен- дуется предоставлять транслятору языка ассемблера возмож- ность определять размер поля для размещения смещения, пред- полагая, что большинство выражений, представляющих операн- ды команд, могут быть вычислены во время трансляции. Можно также рекомендовать вместо использования размера поля пред- ставления смещения, принимаемого по умолчанию, устанавли- вать его равным слову во всех случаях, за исключением очень больших программ; иначе при неизвестном Хна этапе трансля- ции) значении смещения операндов, использующих адресацию «смещением к СК», для размещения этого смещения будет вы- делено длинное слово памяти. Напомним, что поле представле- ния смещения размером слово позволяет адресоваться к любой
248 Глава 8 области памяти, отстоящей от данной команды не более чем на 32 767 байт. Это весьма большое адресное пространство. При использовании прямой или косвенной адресации «смеще- нием к РОН» и при условии, что значение смещения известно, для его размещения транслятор языка ассемблера выбирает поле минимального размера (байт, слово или длинное слово). Если же значение смещения неизвестно, то транслятор выделяет для смещения область памяти размером слово. Этот принимаемый по умолчанию размер поля представления смещения не может быть изменен. Если окажется, что это поле слишком мало, то системная программа LINK обнаружит эту ситуацию и на тер- минале появляется сообщение об ошибке. Однако программист может указать размер поля представ- ления смещения для подобных операндов так же, как это де- лается при адресации «смещением к СК». Например, в команде MOVW B~CLASS_O (R5), R6 указано, что значение смещения, представленного символическим именем CLASS-O, подлежит размещению в однобайтовом поле машинного кода команды. Это означает, что символическому имени CLASS-0 будет присвоено число размером (длиной) байт, которое неизвестно на момент трансляции программы. Когда указанные в командах размеры полей представления смещения оказываются недостаточными для размещения числовых значе- ний этих смещений, программа LINK обнаруживает эти ситуации и выдает сообщения об ошибках. Поскольку величины смещения часто не выходят за пределы диапазона значений размером 1 байт, целесообразно размер поля представления смещения задать посредством знака унар- ной операции ВЛ. Когда же известно, что для представления смещения поля размером слово недостаточно, рекомендуется воспользоваться знаком унарной операции L". Это в конечном Счете сократит время, затрачиваемое на исправление программы и ее повторную трансляцию и редактирование, и тем самым при- несет положительный эффект. Выводы 1. Косвенная адресация — это указание местоположения ад- ресов операндов, над которыми выполняются операции данной команды, а не местоположения самих операндов. 2. Регистровая косвенная адресация — это простейшая фор- ма косвенной адресации, при которой адрес операнда поме- щается в регистр, а имя этого регистра, указываемое в поле операнда команды, заключается в круглые скобки.
Косвенная адресация 249 3. Адресация с автоувеличением адреса — это регистровая косвенная адресация со встроенным механизмом автоматиче- ского увеличения значения адреса на величину, определяемую контекстом команды. Хотя этот режим адресации предназначен для обращения к элементам массива, индексирование представ- ляется более предпочтительным во всех случаях, когда харак- тер задачи допускает его использование. 4. Адресация с автоуменьшением адреса — это регистровая косвенная адресация со встроенным механизмом автоматиче- ского уменьшения адреса на величину, определяемую контек- стом команды. Этот режим адресации оказывается полезным для организации обработки элементов массива в порядке, обратном их размещению в памяти. 5. Регистровая косвенная адресация, адресация с автоувели- чением или автоуменьшением адреса могут включать и индек- сирование. В сочетании с указанными режимами адресации ин? дексирование реализуется точно так же, как и в случае относи- тельной адресации «смещением к СК»; часть операнда, кроме указателя индексного регистра, определяет базовый адрес мас- сива; индекс добавляется к базовому адресу во время выполне- ния программы для формирования действительного адреса эле- мента массива. 6. Адресация «смещением к РОН» позволяет задавать сме- щение с помощью регистровой косвенной адресации. Она оказы- вается полезной для адресации отдельных полей записей данных. 7. Относительная косвенная адресация использует механизм относительной адресации «смещением к СК» для указания адре- сов полей, содержащих адреса операндов. Этот режим адреса- ции задается путем указания перед операндом знака «@». Та- кая адресация допускает использование индексирования. 8. Двухуровневая косвенная адресация предполагает, что в операнде команды указывается адрес области памяти, содержа- щей адрес, по которому может быть найдено само значение опе- ранда. Такая адресация может быть задана в форме регистро- вой косвенной адресации, адресации «смещением к РОН», адре- сации с автоувеличением адреса путем помещения перед опе- рандом знака «@». Соответствующие такому заданию формы адресации называются соответственно регистровой двойной кос- венной адресацией, косвенной адресацией «смещением к РОН», косвенной адресацией с автоувеличением адреса. 9. Размеры полей представления смещения в машинном коде при относительной адресации «смещением к СК» или «смеще- нием к РОН» могут быть указаны в команде посредством зна- ков соответствующих унарных операций или с помощью дирек- тивы .DEFAULT.
250 Глава 8 Новые команды MOVAB MOVAL MOVAQ MOVAW Новые директивы .ADDRESS .DEFAULT Новые режимы адресации Косвенная с автоувеличением адреса Косвенная «смещением к РОН» Косвенная «смещением к СК» Регистровая двойная косвенная Регистровая косвенная С автоувеличением адреса С автоуменьшением адреса «Смещением к РОН» Новые указатели типа операнда В"' L~ W" Новые термины Адресация «смещением к РОН» Двухуровневая косвенная адресация Косвенная адресация Вопросы и упражнения 1. Объясните назначение в системе VAX четырех различных команд пересылки адреса MOV Ах. 2. Объясните, почему в тех случаях, когда это представляет- ся возможным, предпочтение отдается индексированию, а не ре- гистровой косвенной адресации. 3. Укажите различие между адресациями с автоувеличением и автоуменьшением адреса. 4. Когда при совместном использовании индексирования и регистровой косвенной адресации осуществляется модификация адреса, обусловленная индексированием: в начале или в конце? 5. Возможно ли использование одного и того же регистра для задания базового адреса и смещения (индекса) или регистровой косвенной адресации? 6. С какой целью чаще всего применяется адресация «смеще- нием к РОН»?
Косвенная адресация 251 7. Поясните, в чем сходство и различие между адресациями «смещением к СК» и «смещением к РОН». 8. Поясните целесообразность включения в набор средств си- стемы VAX относительной косвенной адресации при наличии регистровой косвенной адресации. 9. Как вычисляется действительный адрес операнда при со- вместном использовании регистровой двойной косвенной адреса- ции и индексирования? 10. В каких случаях для транслятора языка ассемблера представляется неизвестным значение операнда-выражения, ис- пользующего адресацию «смещением к СК»? 11. Как можно изменить размер поля размещения смещения, принимаемый транслятором по умолчанию, в тех случаях, когда значение смещения представляется ему неизвестным? 12. Переведите приводимые ниже команды на языке ассемб- лера системы VAX в соответствующие им машинные коды и укажите шестнадцатеричные значения операндов (а не их адре- сов) каждой команды. Предполагается, что в регистрах и об- ластях памяти находятся следующие числа: 0000 0109 : 0000 0108 : R1 R2 0000 0100 : R3 0000 01 ОС : R4 0000 0104 : R5 0000 0001 : R6 0000 01 ОС : 104 0000 010А : 108 0000 0108 : ЮС a) SUBL2 (R2), R5 б) CLRW B"3(R1) в) INCW @W~4(R3) г) ADDL2 (R5)+, — (R4) д) MULL2 L~8(R3)[R6], R4 е) DIVW2 W~8(R3), R2 Напишите на языке ассемблера системы VAX и выполните отладку программ для решения следующих задач. 13. Исходные данные: целое число LENGTH, за которым сле- дует LENGTH целых чисел; LENGTH < 101. Искомый результат: последовательность исходных чисел, в которой все отрицательные числа предшествуют всем положи- тельным, причем в остальном величины расположены в той же последовательности, в которой они вводятся в машину.
252 Глава 8 Замечание. В этом упражнении не разрешается использовать индексирование. 14. Исходные данные: последовательность целых отрицатель- ных чисел (количество которых меньше 100); за ними в машину вводится положительное целое число. Искомый результат: выраженное в процентах относительное количество исходных чисел, значения которых не выходят за пределы диапазона ±5 от среднего арифметического исходных чисел. Если, например, среднее арифметическое равно 243, то границами указанного диапазона являются числа 238 и 248. Замечание. Использовать индексирование не разрешается. 15. Исходные данные: последовательность положительных це- лых чисел в порядке возрастания их значений, за которой в ма- шину вводится целое отрицательное число и еще пять целых по- ложительных чисел. Общее количество положительных чисел меньше 100. Искомый результат: последовательность исходных чисел с пятью дополнительными числами, вставленными в эту последо- вательность таким образом, что её упорядоченность не меняется. Замечание. Для указания базового адреса массива исполь- зуйте косвенную адресацию, а для адресации отдельных элемен- тов массива — индексирование. 16. Исходные данные: последовательность положительных це- лых чисел, количество которых меньше 1000; за этими числами в машину вводится целое отрицательное число. Искомый результат: последовательность из не равных друг другу исходных чисел (в предположении, что таких найдется менее 100). Замечание. При решении этой задачи для размещения исход- ных данных следует использовать массив областей памяти раз- мером слово каждая. Необходимо воспользоваться косвенной адресацией для задания базового адреса массива и индексиро- ванием для адресации элементов массива. 17. Исходные данные: целое число LENGTH, за которым сле- дует LENGTH целых чисел. Значения чисел не выходят за пре- делы диапазона от —100 до +100. LENGTH < 100. Искомый результат: а) последовательность положительных чисел из общего количества исходных, б) последовательность отрицательных чисел из общего количества исходных. Замечание. Нулевые значения, встречающиеся в исходных данных, игнорируются. Необходимо использовать косвенную адресацию для обращения к массиву исходных данных и мас- сиву положительных чисел, но не разрешается её применять при работе с массивом отрицательных чисел. 18. Исходные данные: целое число LENGTH, за которым сле- дует две последовательности целых чисел, упорядоченных по
Косвенная адресация 253 возрастанию значений этих чисел. Каждый список содержит LENGTH величин. Искомый результат: последовательность, которая составлена из всех исходных чисел, расположенных в порядке возрастания их значений. Замечание. Нельзя просто поместить все исходные числа в один массив, а затем выполнить их упорядочение. Каждое число должно помещаться в надлежащую позицию результирующей последовательности только с помощью одной операции пере- сылки. Для решения этой задачи не разрешается использовать индексирование. 19. Решите задачу, указанную в п. 17, путем помещения адресов двух массивов в таблицу, загрузки адреса этой таблицы в регистр и использования режима косвенной адресации «смеще- нием к РОН» при всех обращениях к элементам обоих масси- вов. 20. Решите задачу, указанную в п. 18, с использованием ре- гистровой двойной косвенной адресации для всех обращений к трем массивам (двум исходным и одному результирующему).
Глава 9 Обработка символьных данных Было время, когда считалось, что вычислительные машины спо- собны выполнять операции необыкновенно быстро и точно, од- нако только над числами. Содержание предыдущих глав тоже посвящено целым числам и операциям над ними. В действи- тельности же цифровые вычислительные машины могут мани- пулировать и данными многих других типов. Одной из наиболее распространенных форм представления информации, обрабатываемой современными ЭВМ, являются тексты или строки символов, представленные соответствующими кодами. Обработка текстов стала обычной для ЭВМ с тех пор, как в начале 50-х годов были созданы первые трансляторы язы- ков программирования. Это обусловлено тем, что трансляция программ, написанных на языках программирования высокого уровня или языке ассемблера, в машинный код сопряжена с вы- полнением разнообразных операций над текстами. 9.1. Кодирование символов и символьные данные В регистры вычислительной машины и ячейки её памяти невоз- можно записать графическое представление символов. Даже при наличии такой возможности осуществлять подобную запись было бы крайне нерационально. Поскольку используемый на практике набор символов сравнительно невелик, можно каж- дому символу поставить в соответствие определенное число и использовать в ЭВМ такое кодированное представление сим- вольных данных. В одном байте памяти машины можно запи- сать 256 различных числовых величин, что позволяет кодировать набор из 256 символов. Этого достаточно для большинства при- менений. ЭВМ системы VAX используют для представления символьных данных в код ASCII (American Standard Code for Information Interchange — Американский стандартный код для обмена ин- формацией), разработанный Американским национальным ин- ститутом стандартов в качестве стандартного кода для всех си- стем передачи данных, включая передачу данных между тер- миналами и ЭВМ по каналам связи общего назначения, таким,
Обработка символьных данных 255 как телефонные линии, а также передачу данных на неболь- шие расстояния по кабелям, связывающим ЭВМ с их перифе- рийным оборудованием. Набор символов кода ASCII включает прописные и строчные буквы алфавита, десятичные цифры, зна- ки пунктуации, используемые в английском языке и в наиболее распространенных языках программирования высокого уровня, и набор специальных символов, применяемых для задания раз- личных управляющих сигналов, передаваемых между ЭВМ и Символ Шестнадцатеричный код А В 41 42 Z 5А а 61 b 62 Z 7А 0 ЗЭ 1 31 • • 9 39 + 2В / 2С / 2F FF ОС (переход на следующую страницу0) LF ОА (переход на следующую строку2*) FF (Form Feed character)—знак, согласно которому позиция печати или отображения информации перемещается на следующую страницу (или другую заранее заданную позицию). — Прим. ред. v LF (Line Feed character)—знак, согласно которому позиция печати или отображения перемещается на следующую строку. — Прим. ред.
256 Глава 9 внешними устройствами. Выше показано представление некото- рых символов в коде ASCII. Представление полного набора символов в коде ASCII дано в приложении С. В качестве примера записи строки символов в коде ASCII ниже показано, как выглядит предложение «Macro is fun!» при его размещении в памяти машины начиная с адреса 300 (шест- надцатеричное представление): Символ Содержимое байта памяти Адрес байта памяти м 4D : 300 а 61 : 301 с 63 : 312 г 72 : 303 о 6F :304 пробел 20 :305 i 69 :306 S 73 :307 пробел 20 : 308 f 66 : 309 и 75 : 39А п 6Е :30В ! 21 : ЗОС Строки символов, используемые в качестве операндов команд языка ассемблера, описываются двумя параметрами: адресом первого байта строки и длиной строки, представляемыми как целые числа без знака размером слово. Заметим, что строки символов размещаются в выделенной для них области памяти так, что самый левый символ строки располагается в поле этой области, имеющем наименьший (самый младший) адрес, т. е. символы записываются в порядке, противоположном тому, в ко- тором размещаются отдельные байты внутреннего представле- ния целого числа размером длинное слово. В языке ассемблера системы VAX предусмотрен ряд дирек- тив для формирования строк символов во время трансляции программы. Простейшая из них директива .ASCII выделяет байт памяти для каждого символа, указанного в её операнде. Опе- ранд должен быть ограничен с двух сторон символом, который не должен появляться в качестве информационного в самой
Обработка символьных данных 257 строке. Символом-ограничителем может быть любой отображае- мый при выводе символ, за исключением пробела, символа та- буляции, знаков « = », «,» или «<». Строка может содержать любые символы, за исключением символов NULL(O), возврата каретки (13ю) или перехода на следующую строку (10ю). Для формирования строки, содержащей на каком-либо своем конце такие символы, следует присвоить (с помощью операторов не- посредственного присваивания) каким-либо символическим име- нам соответствующие этим символам числовые значения (в коде ASCII), а затем записать эти имена, заключенные в угловые скобки, на требуемом конце строки, задаваемой в операнде ди- рективы. Пример 9.1 иллюстрирует данный прием кодирования. 'А Пример 9.1. Директива .ASCII CR=13 LF= 10 STRING__1: .ASCII 'MERRY CHRISTMAS' (CR)(LF> STRING-2: .ASCII * IT'S TOO EARLY?* STRING.3: .ASCII %*** NO IT ISN'T*** % Чтобы пользоваться строками символов, обычно програм- мисту необходимо знать длины этих строк, измеренные в байтах. Длина неизменяемой в ходе выполнения программы строки сим- волов, играющей роль константы, может быть определена раз- личным способом. Программист может подсчитать эту длину вручную или в строке программы, следующей за директивой .ASCII, поместить метку, а затем присвоить некоторому новому символическому имени величину разности между двумя адре- сами. Способ определения длины строки, более точный, чем первый, и менее громоздкий, чем последний, заключается в ис- пользовании модификации директивы .ASCII, называемой .ASCIC. Директива .ASCIC использует тот же самый операнд, что .ASCII для формирования в памяти строки символов, представ- ленных в коде .ASCII, но она также подсчитывает количество байтов, занимаемых строкой, и присваивает это значение байту памяти, предшествующему первому символу строки. В примере 9.2 строки, определяемые операторами программы с метками STR1NG-1 и STRING-2, идентичны. Адресом области, определяемой директивой .ASCII, в которую поме- щается указанная в операнде строка символов, и адресом следующего поля программы. — Прим. пер. 9 Зак. 483
258 Глава 9 А Пример 9.2. Сопоставление директив .ASCII и .ACIC STRING, 1: .ASCIC 'VAX FOR PRESIDENT' STRING,2: .BYTE 17 .ASCII 'VAX FOR PRESIDENT' Строки символов, представленных в коде ASCII, можно фор- мировать с помощью директивы .BYTE, записывая в поле ее операнда код ASCII каждого символа строки один за другим. Однако это утомительно для программиста, а следовательно, сопряжено с появлением ошибок. В полях операндов некоторых команд языка ассемблера си- стемы VAX строки символов могут задаваться в виде литера- лов. Формат строки, представляемой подобным образом, имеет следующий вид: =#= ~ заключенная- в- символы-ограничители- строка Длина строки не может быть больше размера операнда, для которого она используется. Так, если строка символов задана как литерал в операнде-источнике команды пересылки MOVW, то она не может содержать более двух символов. Если строка, указанная в операнде команды в виде литерала, слишком ко- ротка, то она дополняется нулями до требуемого размера опе- ранда. Отметим, что в данном случае это «числовые» нули (цифры 0), а не представление цифры 0 в коде ASCII (30 в ше- стнадцатеричной системе счисления). При выполнении следующей команды пересылки MOVL # ~ А/VAX/, R7 в регистр R7 загружаются данные, имеющие в коде ASCII пред- ставление 3 2 10 00 58 41 5б1 :R7 что соответствует следующему представлению в виде символов: 3 2 10 null X A V~| :R7 9.2. Ввод и вывод символьных данных После освоения принципов формирования в программе символь- ных данных как констант необходимо познакомиться со сред- ствами ввода символических данных в память машины с целью их последующей обработки. Команда READ,A позволяет про-
Обработка символьных данных 259 честь строку символов с внешнего устройства (терминала) в па- мять 1J. В команде используется только один операнд, задаю- щий адрес области памяти, в которую нужно поместить строку. Например, команда READ_A MESSAGE обеспечивает получение всех символов, вводимых с терминала, за исключением символов возврата каретки и перевода строки, и их запись в память в коде ASCII начиная с адреса, задавае- мого символическим именем MESSAGE. Максимальный размер строки, которая может быть прочитана по команде READ.A, составляет 80 символов. Если по команде READ_A вводится большее число символов, чем может вместить в себя область с указанным в команде адресом, то оставшаяся часть строки символов просто помещается в следующую, смежную область памяти, изменяя ее содержимое. Команда PRINT-A выводит на печать (или отображает на терминале) строки символов, представленных в коде ASCII. В команде указываются три параметра (операнда): заголовок (или метка) выводимой информации, указываемый в поле пер- вого операнда команды в виде литерала; длина строки, задавае- мая вторым операндом команды и равная целому числу без зна- ка размером слово; адрес подлежащей выводу строки, разме- щаемый в поле третьего операнда. В приводимом далее примере осуществляется вывод следующего текста: РОЕМ TITLE: MARY HAD A LITTLE LAMB. Д Пример 9.3. Использование команды PRINT-A MESSAGE: .ASCIC 'MARY HAD A LITTLE LAMB' LENGTH: .BLKW 1 ♦ ♦ MOVZBW MESSAGE, LENGTH PRINT-A '''POEM TITLE:', LENGTH, MESSAGE+ 1 Обратите внимание на удобство использования директивы .ASCIC для получения длины строки символов. Однако в после- дующем изложении часто для вычисления длины строки ис- пользуются другие способы, особенно в тех случаях, когда строки формируются в процессе выполнения программы с целью их последующего вывода. 9 Строго говоря, READ_А — макрокоманда; автор называет ее коман- дой только потому, что это понятие вводится и объясняется позже, в гл. 11.— Прим, ред^
260 Глава 9 9.3. Обработка символьных данных В данном разделе описывается сортировка алфавитно-цифровых данных, сканирование текста с целью поиска или пропуска опре- деленных символов, а также поиск определенных комбинаций символов (подстрок) в строках символов. 9.3.1. Сортировка символьных данных Сортировка данных представляет собой одно из наиболее рас- пространенных применений ЭВМ. Хотя очень часто сортировка выполняется над числовыми данными, имеются также задачи, связанные с сортировкой алфавитно-цифровой или текстовой ин- формации. Именно этим объясняется присущая большинству ЭВМ способность осуществлять сортировку алфавитно-цифро- вой информации, представленной в памяти ЭВМ в соответствую- щем коде. Упорядоченная последовательность значений кода, исполь- зуемого для описания символов, определяет порядковые номера (порядок) кодируемых символов. При кодировании символов посредством кода ASCII его значения, используемые для пред- ставления букв алфавита, образуют возрастающую числовую последовательность: значение кода буквы А меньше, чем кода буквы В, и т. д. Команды сравнения строк символьных данных воздействуют на биты-индикаторы (биты признака результата слова состояния процессора) точно так же, как и команды СМРх используемые в системе VAX для сравнения целых чи- сел. Поскольку большинство алгоритмов сортировки предусмат- ривает перестановку местами элементов сортируемых данных, то необходимы также команды пересылки, осуществляющие пе- ресылку строк символов подобно тому, как команды MOVx пе- ресылают целые числа. В системе VAX предусмотрены две команды для сравнения строк символов: одна (СМРСЗ) содержит три операнда, другая (СМРС5)—пять. Команда СМРСЗ имеет следующий формат: СМРСЗ длина, строка_1, строка_2 Операнд длина воспринимается системой как целое число без знака размером слово, указывающее в байтах длину двух строк символов, задаваемых во втором и третьем операндах команды своими адресами. Команда СМРСЗ используется для попарного сравнения сим- волов двух строк; просмотр символов осуществляется последо- вательно слева направо. Обнаружение пары несовпадающих сим- волов отражается на состоянии индикаторов Z и N (битов Z и N признака результата), при этом выполнение команды прекра-
Обработка символьных данных 261 щается. Биту N присваивается значение 1, если числовое зна- чение кода символа первой из сравниваемых строк меньше зна- чения кода символа второй строки; в противном случае биту N присваивается значение 0. Если все символы сравниваемых строк попарно совпадают (строки «равны»), то биту Z присваивается значение 1, в противном случае — значение 0. Такие значения указанных битов признака результата делают использование команд условной передачи управления столь же естественным, как и в случае их применения после команд сравнения целых чисел. Команда СМРСЗ, так же как и другие команды манипулиро- вания символьными данными, использует некоторые регистры процессора с младшими номерами. В результате выполнения команды содержимое этих регистров меняется. Это явление получило название побочного эффекта выполнения команды. Часть данных, формируемых таким образом в указанных реги- страх, содержит информацию, полезную для оценки результата выполнения команды СМРСЗ. Команда СМРСЗ использует регистры R0 и R2 в качестве счетчиков числа символов первой и второй строк соответственно, указанных в операндах команды, сравнение которых на совпа- дение не производилось. После выполнения команды содержимое регистров оказывается равным нулю только тогда, когда срав- ниваемые строки полностью совпадают. Поскольку обе строки имеют одну и ту же длину, содержимое регистра R2 всегда равно содержимому регистра R0. После выполнения команды СМРСЗ, приводимой в примере 9.4, содержимое каждого регистра R0 и R2 равно 4. Д Пример 9.4. Команда СМРСЗ STR_1: .ASCII 'MARYANNE' STR_2: .ASCII 'MARYLYNN' СМРСЗ #8, STR_1, STR_2 Команда СМРСЗ использует регистры R1 и R3 в качестве указателей двух сравниваемых строк: R1 —первой строки, R3 — второй. После выполнения команды в регистре R1 находится адрес символа первой строки, на котором завершается операция (это первый символ, не совпадающий с соответствующим ему символом второй строки). Адрес соответствующего символа вто- рой строки находится в регистре R3. Если две строки, адресуе- мые операндами команды, совпадают, то регистр R1 содержит адрес первого байта, следующего за концом первой строки, а
262 Глаза 9 R3— адрес первого байта, следующего за концом второй строки. Во фрагменте программы примера 9.4 в регистре R1 окажется адрес, равный сумме адреса, соответствующего символическому имени STR.1, и числа 4, а в регистре R3 — адрес, равный сумме адреса, соответствующего символическому имени STR.2, и числа 4. Теперь читателю должно стать понятным, почему во всех ра- нее приведенных программах для индексирования и косвенной адресации использованы регистры со средними значениями но- меров. Регистры с младшими номерами следует использовать только в тех случаях, когда потребность в регистрах возникает на короткий интервал времени, например для хранения проме- жуточных результатов вычисления арифметических выражений. Часто необходимо сравнивать две строки различной длины. Предположим, например, что анализируются слова, встречаю- щиеся в некотором тексте (стихотворении или программе), и не- обходимо сформировать таблицу уникальных (различных) слов текста. Для этого нужно сравнивать все встречающиеся в тек- сте слова с ранее помещенными в таблицу. Нет оснований по- лагать, что длина всех слов одинакова. Для решения подобных задач в языке ассемблера системы VAX имеется команда СМРС5 следующего формата: СМРС5 длина_1, строка_1, симзо л-заполнитель, длина _2, строка_2 Первые два операнда указывают длину в байтах, задавае- мую целым числом без знака размером слово, и адрес первой из сравниваемых строк. Третий операнд—это символ-заполни- тель, восполняющий дефицит символов, возникающий после того, как исчерпаны все символы более короткой из сравнивае- мых строк. Последние два операнда указывают длину и адрес второй из сравниваемых строк точно так же, как первые два операнда. Если обе строки имеют одинаковую длину, выполнение команды СМРС5 подобно выполнению команды СМРСЗ. Если длины строк не одинаковы, процесс попарного сравнения их символов продолжается до тех пор, пока не окажутся исчерпан- ными все символы более короткой строки или не будет обнару- жена пара несовпадающих символов. Если просмотр более ко- роткой строки завершен, а пара отличающихся друг от друга символов так и не встретилась, то выполнение команды СМРС5 продолжается и оставшиеся символы более длинной строки сравниваются с указанным в команде символом-заполнителем. Результат выполнения команды СМРС5 оказывает такое же воздействие на биты-индикаторы PSW (биты признака резуль- тата), как и результат выполнения команды СМРСЗ.
Обработка символьных данных 263 Рассмотрим следующий пример. Д Пример 9.5. Использование команды СМРС5 STR_1: .ASCIC STR_2: .ASCIC LEN_1: .BLKW LEN_2: .BLKW 'MARY' 'MARYLOU' 1 1 MOVZBW STR_1, LEN_1 MOVZBW STR_2, LEN_2 CMPC5 LEN_1, STR-1, #~A//, LEN_2,— STR_2 Операция сравнения прекращается после сопоставления бук- вы L в слове MARYLOU с символом-заполнителем (в данном случае пробелом). Поскольку букве L в коде ASCII соответ- ствует шестнадцатеричное число 4С, а пробелу — число 20, то биту N признака результата присваивается значение 1, а биту/ значение 0. Присвоение биту N значения, равного 1, указывает, что согласно принятому в коде ASCII порядку символов алфа- вита, первая строка «опережает» вторую. Дополнение более ко- роткой строки пробелами до размера длинной строки является типичной операцией при сравнении двух строк с помощью команды СМРС5. Команда СМРС5 использует четыре регистра с младшими номерами точно так же, как и команда СМРСЗ. Регистр R0 используется как счетчик количества символов первой строки, оставшихся не обработанными командой, включая символ, на котором завершается операция сравнения. Содержимое реги- стра R0 оказывается равным нулю только в том случае, когда обе строки символов, адресуемые операндами команды СМРС5, имеют одинаковую длину и идентичный набор символов или если все символы первой из сравниваемых строк оказываются полностью использованными операцией сравнения прежде, чем она завершается. Регистр R1 используется в качестве указателя местоположе- ния первой из сравниваемых строк. После выполнения команды в этот регистр помещается адрес символа этой строки, на кото- ром завершается операция сравнения. Если в процессе сравне- ния строк использованы все символы первой строки, то в ре- гистре R1 оказывается адрес байта, следующего непосредствен- но за последним символом первой строки.
264 Глава 9 Регистр R2 играет роль счетчика символов второй из сравни- ваемых строк, а регистр R3 — указателя местоположения сим- волов этой строки. В примере 9.5 содержимое регистра R0 устанавливается рав- ным 0; в регистр R1 помещается результат сложения значения адреса строки STR-1 с числом 4; в регистр R2 записывается число 3 (количество оставшихся символов, включая тот, на ко- тором прекращается процесс попарного сравнения символов двух строк), а в регистр R3 результат сложения значения ад- реса строки STR.2 с числом 4. Команды MOVC3 и MOVC5 очень похожи по формату на команды СМРСЗ и СМРС5. В команде MOVC3 три операнда: длина строки и адреса двух строк. В команде MOVC5 пять опе- рандов, в том числе и символ-заполнитель. Команда MOVC3 имеет следующий формат: MOVC3 длина, строка-1, строка_2 Как и в команде СМРСх, значением операнда длина явля- ется целое число без знака размером слово. Две строки, кото- рыми манипулирует команда, представлены в ее формате свои- ми адресами. В примере 9.6 команда MOVC3 пересылает цели- ком копию строки символов, расположенных в области памяти с адресом STR_1 в область памяти с адресом STR_2. А Пример 9.6. Применение команды MOVC3 STR.l: .ASCII 'APPLES ARE GOOD FOR YOU' STR.2: .BLKB 23 LENGTH: .BLKW 1 MOVZBW MOVC3 STR.l, LENGTH LENGTH, STR_1 + 1, STR.2 Команда MOVC3 использует первые шесть регистров (реги- стры с младшими номерами). В регистр R1 помещается адрес байта, непосредственно следующего за последним символом пересылаемой строки, а в регистр R3 — адрес байта, непосред- ственно следующего за последним байтом принимающей обла- сти. Таким образом, содержимое этих регистров устанавлива- ется равным значениям адресов начала областей памяти, ко- торые задаются операндами строка-1 и строка-2, увеличенными на длину пересылаемой строки символов. Хотя при выполнении команды MOVC3 используются и регистры RO, R2, R4 и R5,
Обработка символьных данных 265 после завершения ее действий в них не остается сколько-нибудь полезной информации. Команда M0VC5 используется для персылки более коротких строк символов в большие по размеру области памяти, и на- оборот (более длинных строк в меньшие по размеру области памяти). Эта команда имеет следующий формат: M0VC5 длина__1, строка_1, символ-заполнитель, длина__2, строка_2 Операнд длина-1 воспринимается системой как целое число без знака размером слово. С его помощью указывается длина строки, адресуемая операндом строка-1. Значением операнда длина-2 должно быть целое число без знака размером слово, указывающее длину строки, адресуемую операндом строка-2. Операнд символ-заполнитель — это символ кода ASCII, исполь- зуемый в тех случаях, когда исходная (пересылаемая) строка {строка-1) является более короткой, чем длина области памяти, адресуемой операндом строка-2. Если исходная строка имеет большую длину, чем принимающая область памяти, то избыточ- ные символы не пересылаются. Рассмотрим в качестве примера следующий фрагмент про- граммы. А Пример 9.7. Использование команды M0VC5 STR_1: .ASCIC 'CHOPIN' STR_2: .ASCIC 'BEETHOVEN' STR-3: .BLKB 8 STR_4: .BLKB 8 LEN-1: .BLKW 1 LEN-2: .BLKW 1 MOVZBW STR-1, LEN-1 MOVZBW STR-2, LEN_2 MOVC5 LEN-1, STR-1 + 1, # "A/*/, # 8, STR_3 MOVC5 LEN-2, STR-2+1, # ~A/*/, #8, STR-4 После выполнения приведенных в примере команд MOVC5 содержимым строки STR-З станет текст CHOPIN**, а строки STR_4 текст BEETHOVE. Пересылка буквы N выполнена не будет. Команду MOVC5 можно использовать не только для пере- сылки строк символов в области памяти с размерами, отличаю- щимися от длин пересылаемых строк, но и для заполнения бло- ком памяти определенными символами. Например, команда MOVC5 #0, STR-2, #~А/ /, # 100, STR_2
265 Глава 9 помещает 100 символов «пробел» в область памяти, начало ко- торой имеет адрес, задаваемый символическим именем STR-2. Отметим, что все команды манипулирования символьными данными определяются так, как будто бы они обращаются к данным размером байт. Следовательно, если для каких-либо операндов этих команд используются режимы адресации с ин- дексированием, автоматическим приращением или автоматиче- ским уменьшением адреса, то благодаря тому, что размер дан- ных подразумевается всегда равным одному байту, не требуется (и не производится) модификация содержимого регистра, ис- пользуемого для учета длины обрабатываемых данных при вы- числении очередного адреса. Изложенное выше позволяет перейти к написанию закончен- ной программы на языке ассемблера, использующей рассмот- ренные в данной главе средства манипулирования символьными данными. А Пример 9.8. 9 Постановка задачи Исходные данные: целое число LENGTH, за которым сле- дует LENGTH имен, каждое из которых содержит не более 20 символов; LENGTH < 101. Искомый результат: исходные имена, расположенные в ал- фавитном порядке путем использования алгоритма сортировки обменом. Приводимое ниже описание решения этой задачи на псевдо- коде реализует тот же самый алгоритм сортировки обменом, ко- торый использован при решении задачи примера 7.2. 6 Алгоритм решения задачи на псевдокоде Ввести число в область памяти LENGTH Ввести массив исходных имен в область памяти NAMES Присвоить содержимому области памяти TOP-LIMIT значение LENGTH-2 Присвоить содержимому области памяти BOT-LIMIT значение LENGTH - 1 FOR TOP_REG := 0 ТО TOP-LIMIT DO Присвоить содержимому области памяти BOT-START значение TOP_REG-[- 1 FOR ВОТ-REG := BOT-START ТО BOT-LIMIT DO IF NAMES [TOP-REG] > NAMES [BOT_REG] THEN поменять эти элементы массива местами ENDIF
Обработка символьных данных 267 END-FOR END-FOR Вывести на печать упорядоченный массив имен Конец программы Описание алгоритма решения этой задачи на языке ассем- блера содержит команды M0VC3, M0VC5 и СМРСЗ. Реализо- вать сортировку обменом массива строк символов труднее, чем массива чисел: основная проблема связана с адресацией от- дельных строк символов, которую выполнить значительно слож- нее, чем адресацию чисел. В системе VAX для представления чисел используются поля стандартных размеров, а поэтому при- меняемое для обращения к содержимому этих полей индекси- рование является весьма простым способом адресации чисел. Для строк символов невозможно подобрать соответствующие поля представления подобных стандартных размеров. А поэтому для непосредственной адресации к отдельным элементам мас- сива, состоящего из строк символов, нельзя использовать ни индексирование, ни адресацию с автоувеличением или авто- уменьшением адреса. Реализация алгоритма сортировки обме- ном на псевдокоде требует использования двух вложенных циклов FOR. Хотя переменные, являющиеся параметрами этих циклов, не могут непосредственно использоваться для адреса- ции сортируемых строк символов, они употребляются для этой цели косвенно. Если желательно проверять индекс адресуемого элемента массива на принадлежность диапазону возможных значений, то можно использовать рассмотренную в гл. 7 команду INDEX. Поскольку рассматриваемый массив строк символов является одномерным, то операнд этой команды нижняя-граница можно положить равным нулю и при этом отпадает необходимость в указании операнда начальное-значение-индекса. Чтобы содер- жимое индексного регистра было корректным, достаточно поло- жить текущее значение индекса и размер элемента равными 20. Значениями операндов нижняя-граница и верхняя-граница должны быть 0 и 99 соответственно. Например, для вывода на печать пятнадцатой 20-символь- ной строки массива строк с именем LIST пригодна следующая последовательность команд: INDEX #14, #0, #99, #20, #0, R6 PRINT-A ^ПЯТНАДЦАТОЕ СЛОВО = ', #20, LIST[R6] Эти команды выполняют указанную задачу корректно только благодаря тому, что LIST является представленным в симво- лической форме адресом байта памяти, а команда PRINT-A предполагает своим контекстом обработку данных размером
268 Глава 9 байт. Если бы операнд LIST [R6] был указан в команде, кон- текст которой предполагал бы манипуляции с данными разме- ром, отличным от байта, то результат вычисления действитель- ного адреса операнда оказался бы некорректным. Если проверка индекса адресуемого элемента массива на принадлежность диапазону возможных значений не требуется, то можно вычислить корректное значение содержимого индекс- ного регистра с помощью команды умножения. Так, для реше- ния той же задачи вывода на печать пятнадцатой 20-символь- ной строки массива с именем LIST пригодны следующие команды: MULL3 #14, #20, R6 PRINT-A ^'ПЯТНАДЦАТОЕ СЛОВО = ', #20, LIST [R6] В приводимом ниже описании на языке ассемблера алго- ритма сортировки обменом команда INDEX используется для адресации строк при выполнении процедуры сортировки. При составлении указанного описания необходимо было решить про- блему адресации к строкам символов как при их вводе, так и при их выводе на печать в качестве результата сортировки. Для этой цели используется относительная косвенная адреса- ция, как более эффективная по сравнению с индексированием и позволяющая еще раз продемонстрировать применение косвен- ной адресации. Для этого адреса строк помещаются в области памяти, являющиеся указателями элементов массива, а затем содержимое этих областей увеличивается на 20 для получения адресов следующих элементов массива строк. Полученная с учетом сделанных замечаний программа на языке ассемблера, описывающая алгоритм сортировки обменом, преследует цель более ясного изложения (на конкретных при- мерах) упомянутых выше способов адресации. • Программа на языке ассемблера СОРТИРОВКА ОБМЕНОМ СПИСКА ИМЕН ИСХОДНЫЕ ДАННЫЕ: ЦЕЛОЕ ЧИСЛО LENGTH, ЗА КОТОРЫМ СЛЕДУЕТ LENGTH ИМЕН. КАЖДОЕ ИМЯ СОДЕРЖИТ НЕ БОЛЕЕ 20 СИМВОЛОВ. LENGTH < 101 ИСКОМЫЙ РЕЗУЛЬТАТ: ИСХОДНЫЕ ИМЕНА, РАСПОЛОЖЕННЫЕ В АЛФАВИТНОМ ПОРЯДКЕ ПОСРЕДСТВОМ АЛГОРИТМА СОРТИРОВКИ ОБМЕНОМ .PSECT EXAMPLE, LONG MAX_NUM_NAMES = 100 ; ОБЛАСТИ ПАМЯТИ ДЛЯ: LENGTH; .BLKL 1 ; КОЛИЧЕСТВА ИСХОДНЫХ ИМЕН
Обработка символьных данных 269 TOP-LIMIT: .BLKL 1 ; МАКСИМАЛЬНОГО ЗНАЧЕНИЯ ПАРАМЕТРА ВНЕШНЕГО ЦИКЛА ПРОЦЕДУРЫ ;СОРТИРОВКИ ВОТ-LIMIT: BLKL 1 ; , МАКСИМАЛЬНОГО ЗНАЧЕНИЯ ПАРАМЕТРА ВНУТРЕННЕГО ЦИКЛА ПРОЦЕДУРЫ СОРТИРОВКИ BOT-START: .BLKL 1 ; ; НАЧАЛЬНОГО ЗНАЧЕНИЯ ПЕРЕМЕННОЙ ВНУТРЕННЕГО ЦИКЛА NAMES: .BLKB 2o’ *MAX_NUM_NAMES МАССИВА ИМЕН TEMP_NAME: .BLKB 20; ; ВРЕМЕННОГО ХРАНЕНИЯ ИМЕНИ NAME-PTR: .BLKL 1 ; УКАЗАТЕЛЯ АДРЕСА ИМЕНИ COUNTER: .BLKL 1 ; СЧЕТЧИКА ВВОДИМЫХ И ВЫВОДИМЫХ ;ДАННЫХ .ENTRY ЕХ_9_8, О INIT-IO ВВОД ЗНАЧЕНИЯ КОЛИЧЕСТВА ИСХОДНЫХ ИМЕН В ОБЛАСТЬ LENGTH PRINT-L ''ЗАДАЙТЕ ДЛИНУ СПИСКА' READ_L LENGTH ; ВВОД МАССИВА ИМЕН В ОБЛАСТЬ ПАМЯТИ NAMES MOVAB NAMES, NAME-PTR • ДЛЯ COUNTER-: = 1 ДО LENGTH ВЫПОЛНЯТЬ В ЦИКЛЕ MOVL # I, COUNTER CMPL COUNTER, LENGTH BLEQ READ-LOOP BRW OUT-READ, LOOP READ-LOOP: ; ВВОД ИМЕНИ MOVC5 #0, NAMES, '‘А/ /, #20, @NAME_PTR PRINT_L ^'ВВЕДИТЕ СЛЕДУЮЩЕЕ ИМЯ READ-A @NAME_PTR ADDL2 #20, NAME-PTR AOBLEQ LENGTH, COUNTER, READ-LOOP ; КОНЕЦ ЦИКЛА «ДЛЯ COUNTER :=...» ; ПРИСВОЕНИЕ СОДЕРЖИМОМУ TOP-LIMIT ЗНАЧЕНИЯ LENGTH-2
270 Глава 9 ; И СОДЕРЖИМОМУ ВОТ-LIMIT ЗНАЧЕНИЯ LENGTH-1 OUT_READ_LOOP: SUBL3 #2, LENGTH, TOP_LIMIT SUBL3 # 1, LENGTH, BOT_LIMIT ; ДЛЯ TOP-REG := О ДО TOP-LIMIT ВЫПОЛНЯТЬ В ЦИКЛЕ CLRL R6 CMPL R6, TOP-LIMIT BLEQ OUTER-LOOP BRW OUT_OUT_LOOP OUTER-LOOP: ;ПРИСВОЕНИЕ СОДЕРЖИМОМУ ВОТ-START ЗНАЧЕНИЯ ; TOP-REG + 1 И ВЫЧИСЛЕНИЕ АДРЕСА ТЕКУЩЕГО ИМЕНИ ; (ЗАПИСЬ АДРЕСА В РЕГИСТР R8) ADDL3 #1, R6, BOT-START INDEX R6, # 0, # 99, # 20, # 0, R8 •ДЛЯ BOT_REG:= ВОТ-START ДО ВОТ-LIMIT ВЫПОЛНЯТЬ ;В ЦИКЛЕ MOVL BOT-START, R7 IN_ LOOP: ; ЕСЛИ NAMES [TOP-REG] > NAMES [BOT.REG] ; (СНАЧАЛА ВЫЧИСЛЕНИЕ АДРЕСА ИМЕНИ, СЛЕДУЮЩЕГО ; ЗА ТЕКУЩИМ, С ЗАПИСЬЮ РЕЗУЛЬТАТА В РЕГИСТР R9) INDEX СМРСЗ BLEQ R7, # 0, # 99, # 20, # 0, R9 #20, NAMES [R8], NAMES [R9] ENDIF ; ЗАТЕМ ПЕРЕСТАНОВКА ТЕКУЩЕГО ИМЕНИ И СЛЕДУЮЩЕГО ; ЗА НИМ МЕСТАМИ MOVC3 MOVC3 MOVC3 #20, NAMES [R8], TEMP_NAME #20, NAMES [R9], NAMES [R8] #20, TEMP_NAME, NAMES [R9] ; КОНЕЦ ОПЕРАЦИИ «ЕСЛИ» ENDIF;
Обработка символьных данных 271 AOBLEQ BOT-LIMIT, R7, IN-LOOP ; КОНЕЦ ЦИКЛА «ДЛЯ BOT.REG := ...» AOBLEQ TOP-LIMIT, R6, OUTER-LOOP ; КОНЕЦ ЦИКЛА «ДЛЯ TOP-REG :=...» OUT-OUT-LOOP: ; ПЕЧАТЬ УПОРЯДОЧЕННОГО СПИСКА ИМЕН PRINT-L "'УПОРЯДОЧЕННЫЙ СПИСОК' PRINT-L ' MOVAB NAMES, NAME-PTR ; ДЛЯ COUNTER := 1 ДО LENGTH ВЫПОЛНЯТЬ В ЦИКЛЕ MOVL # 1, COUNTER CMPL COUNTER, LENGTH BLEQ PRINT-LOOP BRW OUT-PRINT-LOOP PRINT-LOOP: PRINT-A #20, @NAME-PTR ADDL2 #20, NAME-PTR AOBLEQ LENGTH, COUNTER, PRINT-LOOP ; КОНЕЦ ЦИКЛА «ДЛЯ COUNTER := ...» OUT-PRINT-LOOP: $EXIT-S .END EX-9-8 9.3.2. Поиск слов в тексте Часто возникает необходимость осуществлять поиск определен- ных слов в некотором тексте. Подобная процедура является неотъемлемой частью программ, выполняющих любые виды трансляции (перевода) текстов, будь то трансляция текста про- граммы на языке ассемблера в машинный код системы VAX или перевод законодательных актов Канады с английского язы- ка на французский. Кроме того, программы, осуществляющие лингвистический анализ, должны иметь возможность находить определенные слова в заданном тексте. Например, частота по- явления слов в тексте и попарная корреляция слов могут по- мочь определить автора текста, поскольку используемые тем
272 Глава 9 или иным писателем сочетания слов выявляют его индивиду- альность подобно отпечаткам пальцев. Сначала рассмотрим простую задачу поиска слов в тексте. Если поиск осуществляется в тексте, для которого единствен- ными допустимыми разделителями слов являются пробелы, то слово определяется как строка символов, не содержащая про- белов. Найти слово в тексте означает определить позицию его первого и последнего символов, а затем вычислить длину слова. Предлагается начинать просмотр текста слева направо, еди- новременно анализируя только один символ. Первый обнару- женный символ, отличный от пробела, является первым симво- лом слова. Подобный просмотр текста следует продолжать до тех пор, пока еще раз не будет обнаружен пробел. Этот пробел является признаком конца слова. Адрес символа, находящегося непосредственно слева от этого пробела, — адрес последнего символа слова. В системе VAX имеются две команды, предназначенные для поиска слов: LOCC (LOCate Character —ОПРЕДЕЛЕНИЕ МЕСТОПОЛО- ЖЕНИЯ СИМВОЛА) и SKPC (SKiP Character — ПРОПУСК СИМВОЛА). Они имеют следующий формат: КОП символ, длина-строки, адрес-строки В поле операнда символ обычно указывается в виде лите- рала один из символов кода ASCII. Операнд длина-строки пред- ставляет собой целое число без знака размером слово, а опе- ранд адрес_строки — выражение, значение которого задает ад- рес строки. Команда LOCC используется для сравнения указанного в качестве первого оператора символа.с каждым символом за- данной строки поочередно слева направо, причем этот процесс продолжается до тех пор, пока либо не будет просмотрена вся строка, либо будет найден символ строки, совпадающий с за- данным. Как именно закончилось выполнение команды LOCC, можно выяснить, проверив значение бита Z признака резуль- тата. Если в строке указанный символ обнаружен, то биту Z присваивается значение 0, в противном случае— 1. Команда LOCC записывает в регистр R0 число, равное количеству сим- волов строки, оставшихся непросмотренными, или 0, если за- данный символ не найден. В регистр R1 загружается адрес пер- вого байта строки, содержащего искомый символ, или адрес первого байта, расположенного непосредственно после строки, если заданный символ в строке не обнаружен. Команда SKPC очень похожа на команду LOCC; выполняе- мые этими командами операции в основном аналогичны. Раз- личие заключается в том, что по команде SKPC сравнение сим-
Обработка символьных данных 273 волов производится до тех пор, пока не встретится символ стро- ки, отличающийся от заданного. Если такое несовпадение об- наружено, биту Z признака результата присваивается значе- ние 0, в противном случае этому биту присваивается значение 1. Так же как и при использовании команды LOCC, по команде SKPC в регистр R0 записывается число, равное количеству сим- волов, которые остались необработанными командой, а в ре- гистр R1— адрес первого необработанного символа строки или адрес первого байта, расположенного непосредственно вслед за строкой, в которой не оказалось символов, не совпадающих с указанным в команде. . Приводимый ниже пример демонстрирует применение этих двух команд. Д Пример 9.9. Команда LOCC STRING: .ASCII "XXXHIYY" LOCC #~A/!/, #8, STRING После выполнения команды LOCC бит Z признака результата становится равным 0, содержимое регистра R0 — 5, а в реги- стре R1 оказывается адрес первого восклицательного знака строки. Предположим, что после приведенной в примере 9.9 коман- ды LOCC выполняется команда SKPC #~А/!/, RO, (R1) В данном случае пропускаются три восклицательных знака. Биту Z признака результата присваивается значение 0, содер- жимое регистра R0 становится равным 2, т. е. числу символов, оставшихся необработанными командой SKPC, а в регистре R1 оказывается адрес первого символа «!» строки. В примере 9.9 команды LOCC и SKPC использованы для поиска определенного слова в строке, хотя последовательность восклицательных знаков, размещенная среди заглавных букв, представляется весьма непривычным словом. Простая задача поиска слов в тексте, описанная в начале данного раздела, во многом подобна рассмотренному примеру. Командой SKPC можно воспользоваться для поиска первого символа слова, а командой LOCC — для поиска последнего сим- вола, указывая пробел в качестве операнда символ этих команд. Если строка содержит только одно слово, задача оказыва- ется весьма простой, о чем свидетельствует пример 9.10.
274 Глава 9 Л Пример 9.10 • Постановка задачи Исходные данные: строка символов, содержащая единствен- ную, не включающую пробелы подстроку. Искомый результат: не содержащая пробелы подстрока, пе- ремещенная в новую область памяти. Описание на псевдокоде решения задачи примера 9.10 бази- руется на материале, изложенном выше в данном разделе. • Алгоритм решения задачи на псевдокоде Ввод строки Поиск начала подстроки, не содержащей пробелы Поиск конца подстроки, не содержащей пробелы Пересылка подстроки в область WORD Вывод на печать содержимого области WORD Конец программы Текст программы на языке ассемблера, реализующей дан- ный алгоритм, является более детальным описанием операций, выполняемых ЭВМ, чем аналогичный текст на псевдокоде. • Программа на языке ассемблера ; ПОИСК В ЗАДАННОЙ СТРОКЕ СИМВОЛОВ, ; ПЕРЕСЫЛКА И ВЫВОД НА ПЕЧАТЬ ; НЕ СОДЕРЖАЩЕЙ ПРОБЕЛЫ ПОДСТРОКИ ; ИСХОДНЫЕ ДАННЫЕ: СТРОКА СИМВОЛОВ, СОДЕРЖАЩАЯ ; ЕДИНСТВЕННУЮ НЕ СОДЕРЖАЩУЮ ; ПРОБЕЛЫ ПОДСТРОКУ ; ИСКОМЫЙ РЕЗУЛЬТАТ: ПЕРЕМЕЩЕННАЯ В НОВУЮ ОБЛАСТЬ ; ПАМЯТИ ПОДСТРОКА СИМВОЛОВ, НЕ СОДЕРЖАЩАЯ ПРОБЕЛЫ .PSECT EXAMPLE, LONG ; ;ОБЛАСТИ ПАМЯТИ ДЛЯ LINE: WORD: .BLKB 80 .BLKB 25 ; ИСХОДНОЙ СТРОКИ СИМВОЛОВ ; HE СОДЕРЖАЩЕЙ ПРОБЕЛЫ ; ПОДСТРОКИ LINE.PTR: .ADDRESS LINE : ; УКАЗАТЕЛЯ СТРОКИ LENGTH: .LONG 80 ; ДЛИНЫ СТРОКИ SKIPPED: .BLKL 1 ; КОЛИЧЕСТВА СИМВОЛОЕ > В ИСКОМОЙ ПОДСТРОКЕ .ENTRY INIT-IO EX_9_10, 0 MOVC5 #0, LINE, А/ /, #80, LINE READ-A LINE
Обработка символьных данных 275 ПОИСК НАЧАЛА (ПЕРВОГО СИМВОЛА) ПОДСТРОКИ SKPC #лА/ /, LENGTH, LINE УСТАНОВКА УКАЗАТЕЛЯ АДРЕСА И ДЛИНЫ ОСТАВШЕЙСЯ ЧАСТИ СТРОКИ MOVL RO, LENGTH MOVL Rl, LINE.PTR • ПОИСК КОНЦА (ПОСЛЕДНЕГО СИМВОЛА) ПОДСТРОКИ LOCC #~А/ /, LENGTH, @LINE_PTR ;ПЕРЕСЫЛКИ ПОДСТРОКИ СЛОВА В ОБЛАСТЬ ПАМЯТИ «WORD» SUBL3 RO, LENGTH, SKIPPED M0VC3 SKIPPED, @LINE_PTR, WORD ;PRINT_A ИСКОМОЕ СЛОВО: SKIPPED, WORD $EXIT_S .END EX_9_10 Процедура усложняется из-за необходимости слежения за значениями длины оставшейся части строки и адреса первого символа, остающегося не обработанным после выполнения команды SKPC. На рис. 9.1 показано, как команды SKPC и LOCC программы примера 9.10 обрабатывают простую строку символов. Чтобы найти все слова в заданной строке текста, сле- дует включить в данную программу команды, реализующие цикл WHILE псевдокода. Условие выполнения операций цикла долж- но определяться состоянием указателя позиций внутри анализи- руемой строки. Рассмотрим несколько более сложную задачу поиска слов в тексте, предполагая, что в качестве символов-разделителей слов (подстрок) текста используются не только пробелы. Такая задача обычно возникает при необходимости подсчета различ- ных знаков пунктуации, используемых для разделения отдель- ных фраз в английском языке. Если для поиска слов в тексте на английском языке нужно применять команды LOCC и SKPC, то понадобится написать отдельный фрагмент программы для каждого возможного знака препинания, завершающего слова или фразу текста. Чтобы упростить решение подобных задач в системе VAX, предусмотрены две команды SPANC и SCANC, по функциональному назначению подобные командам LOCC и SKPC. При разработке подобных команд приходится решать сле- дующую проблему: каким количеством команд должен распо-
276 Глава 9 Рис. 9.1. Выполнение команд SKPC и LOCC примера 9.10. лагать программист для описания требуемого решения, т. е. сколь детально должен он управлять реализацией необходимых функций. Так, для поиска нескольких символов в строке можно предложить только одну команду, содержащую список этих символов, или же несколько команд, последовательность кото- рых указывает программист. Разработчики системы VAX при- няли компромиссное решение, включив в набор команд две команды, требующие от пользователя выделения программными средствами блока памяти и учета некоторых конкретных осо- бенностей реализации процедуры поиска. Применение команд SCANC и SPANC требует построения 256-байтовой таблицы трансляции кодов. Каждой позиции таб- лицы соответствует одно из возможных значений, которое мо- жет быть записано в байте памяти: 96 позициям таблицы соот- ветствуют представления символов в коде ASCII. В каждую позицию таблицы нужно записать информацию, указывающую, следует ли предпринимать действия при обнаружении в обра- батываемой строке символа, соответствующего данной позиции таблицы. Каждый бит содержимого позиции (байта) таблицы может быть использован для указания действия, выполняемого коман- дой SCANC или SPANC. Следовательно, 256 возможных кодо- вых комбинаций можно разделить на 8 различных групп.
Обработка символьных данных 277 (С точки зрения выполняемых действий эти группы не являются взаимоисключающими.) Например, для того чтобы команда SCANC прекращала просмотр заданной строки при обнаруже- нии запятой или точки, необходимо, чтобы один из битов со- держимого в 45-й и 47-й позициях таблицы был равен 1, а по- добный же бит содержимого всех других позиций таблицы был равен 0 (в коде ASCII запятой и точке соответствуют десятич- ные числа 45 и 47 соответственно). Это можно реализовать, поместив код 1 в 45-ю и 47-ю позиции таблицы и код 2 — во все остальные позиции. В последующем изложении в команде SCANC указывается 1 в тех случаях, когда необходимо прекра- тить «сканирование» строки при обнаружении запятой или точки. Команда SCANC обрабатывает символы заданной строки поочередно слева направо, используя каждый символ как ин- декс элемента таблицы. Содержимое соответствующей позиции таблицы посредством логической операции И сравнивается с числом, указанным в команде. Сравнение осуществляется для всех восьми пар битов, образованных битами символа строки и битами машинного кода числа, указанного в команде. Ре- зультат операции сравнения не равен нулю, если хотя бы одна пара битов имеет значения, равные 1. Как только при обработке очередного символа строки результат операции И отличен от нуля, выполнение команды прекращается и биту Z признака результата присваивается значение 0. Если ни одного такого символа в строке не обнаружено, биту Z присваивается значе- ние 1. В результате выполнения команды SCANC в регистре R0 записывается число, равное количеству символов строки, остав- шихся непросмотренными (включая символ, удовлетворяющий условию поиска и вызывающий завершение просмотра строки), или 0, если требуемый символ не найден. Содержимое реги- стра R0 проверяется с целью присвоения биту Z признака ре- зультата соответствующего значения: 0, если условие поиска удовлетворяется, и 1 — в противоположном случае. В ре- гистр R1 записывается адрес символа строки, для которого удовлетворяется условие поиска, или адрес байта, следующего непосредственно за последним символом строки, если такой символ не обнаружен в строке. Регистры R2 и R3 также исполь- зуются во время выполнения команды, но в них не остается ка- кой-либо полезной информации. Одному из битов любого байта таблицы, используемой при выполнении команды SCANC, мож- но присвоить значение 1, записав в этот байт одно из следую- щих чисел: 1, 2, 4, 8, 16, 32, 64 или 128. Для присвоения еди- ничных значений одновременно нескольким битам байта таб- лицы можно воспользоваться другими числами; это оказывается
278 Глава 9 полезным, когда для поиска символа используется одна и та же таблица и несколько команд (SCANC или SPANC) с различ- ными числами, указанными в качестве последнего операнда команды (см. далее формат этих команд). Например, если в программе требуется команда SCANC для поиска знаков пунктуации, то во всех позициях таблицы, соответствующих знакам пунктуации, определенному биту нужно присвоить зна- чение, равное 1. Но если, кроме того, необходим поиск в тексте знаков «точка», то содержимому элемента таблицы, соответ- ствующего этому знаку, должен быть присвоен другой код, включающий, однако, двоичную единицу в том разряде байта, который является местоположением бита, — признака знака пунктуации. Так, используя целое число 3 для кодирования в таблице знака «точка», а число 1 — для кодирования любого другого знака пунктуации, в качестве последнего операнда команды SCANC следует указывать число 1 для поиска любых знаков пунктуации и число 3 для поиска знака «точка». По- скольку двоичный код числа 3 содержит двоичную единицу в первом разряде, как и двоичный код числа 1, предлагаемое решение корректно. Команда SPANC выполняется точно так же, как и команда SCANC, за исключением того, что просмотр символов строки продолжается до тех пор, пока результат операции И над двумя байтами — содержимым элемента таблицы, соответствующего очередному символу строки, и числом, указанным в команде,— не оказывается равным 0. Это происходит, когда при сравнении (посредством логической операции И) двух очередных байтов не удается обнаружить пары соответствующих битов, имеющих единичные значения. Нулевой результат операции И приводит к присвоению значения 0 биту Z признака результата; в про- тивном случае этому биту присваивается значение 1. Четыре регистра с младшими номерами используются точно так же, как и при выполнении команды SCANC. Например, для про- пуска подстроки, содержащей запятые и точки, пригодны команды SPANC с числом 1 в качестве последнего операнда и таблица, ранее использованная при поиске первой запятой или точки с помощью команды SCANC. Команды SCANC и SPANC имеют следующий формат: КОП длина, строка, таблица, число Операнд длина используется для указания длины обрабатывае- мой строки и воспринимается как целое число без знака раз- мером слово. Операнды строка и таблица являются адресами обрабатываемой строки и таблицы трансляции кодов соответ- ственно. Операнд число всегда задается в виде целого числа размером байт.
Обработка символьных данных 279 Таблица трансляции кодов может быть построена с помощью директивы .BYTE при использовании ее необязательного опе- ранда коэффициент-повторения. Приводимый ниже пример демонстрирует использование и выполнение команд SCANC и SPANC. Д Пример 9.11 • Постановка задачи Исходные данные', строка символов, содержащая подстроку строчных букв. Искомый результат', подстрока строчных букв. Эта задача подобна задаче примера 9.10, за исключением того, что искомое слово текста (подстрока) может содержать только строчные буквы. Кроме того, вместо использования про- белов в качестве так называемых стоп-символов (при обнару- жении которых прекращается выполнение команд просмотра строки) предлагается для определения конца строки примене- ние набора строчных букв в операциях пропуска символов стро- ки, предшествующих определенному символу (span), и поиска определенного символа (scan). Прежде всего необходимо построить таблицу трансляции ко- дов. Для этой цели в позиции таблицы, соответствующие строч- ным буквам кода ASCII, записывается код числа 1, а во все остальные позиции — код числа 2. Это дает возможность ука- зывать число 1 для задания ограничителя слова в каждой команде SCANC и SPANC: в SCANC для поиска в строке пер- вой строчной буквы, а в SPANC для поиска первого символа, не являющегося прописной буквой. Описание на псевдокоде решения задачи примера 9.11 столь похоже на аналогичное описание задачи примера 9.10, что нет смысла его здесь повторять. • Программа на языке ассемблера ; поиск и ВЫВОД НА печать подстроки СТРОЧНЫХ БУКВ i ИСХОДНЫЕ ДАННЫЕ; СТРОКА СИМВОЛОВ, СОДЕРЖАЩАЯ ; ПОДСТРОКУ СТРОЧНЫХ БУКВ ; ИСКОМЫЙ РЕЗУЛЬТАТ: ПОДСТРОКА СТРОЧНЫХ БУКВ .PSECT EXAMPLE, LONG TABLE: .BYTE 2 [97], 1 [26], 2 [133] ; ТАБЛИЦА ТРАНСЛЯЦИИ КОДОВ ; ОБЛАСТИ ПАМЯТИ ДЛЯ LINE: .BLKB 80 ; ИСХОДНОЙ СТРОКИ СИМВОЛОВ LINE-PTR: .ADDRESS LINE ; АДРЕСА ПЕРВОГО ; ; НЕПРОСМОТРЕННОГО СИМВОЛА LENGTH: .LONG 80 ; ДЛИНЫ ОСТАВШЕЙСЯ ЧАСТИ
280 Глава 9 ; СТРОКИ SKIPPED: .BLKL 1 ; КОЛИЧЕСТВА ПРОПУЩЕННЫХ ; СИМВОЛОВ WORD: .BLKB 25 ; ИСКОМОЙ ПОДСТРОКИ .ENTRY INIT_IO MOVC5 READ_A ЕХ_9_11, 0 #0, LINE, #^А/ /, #80, LINE LINE ; ПОИСК НАЧАЛА ПОДСТРОКИ SCANC LENGTH, @LINE_PTR, TABLE, #1 ; УСТАНОВКА НОВОГО СОДЕРЖИМОГО УКАЗАТЕЛЯ (АДРЕСА ОБ ; ЛАСТЕИ ПАМЯТИ) И ДЛИНЫ ОСТАВШЕЙСЯ ЧАСТИ СТРОКИ MOVL RO, LENGTH MOVL Rl, LINE_PTR ; ПОИСК КОНЦА ПОДСТРОКИ SPANC LENGTH, @LINE_PTR, TABLE, # 1 ; ПЕРЕСЫЛКА ПОДСТРОКИ В ОБЛАСТЬ «WORD» SUBL3 RO, LENGTH, SKIPPED MOVC3 SKIPPED, @LINE_PTR, WORD PRINT_A ИСКОМОЕ СЛОВО:', SKIPPED, WORD $EXIT_S .END EX_9_11 Как и написанная на языке ассемблера программа примера 9.10, данная программа может быть взята за основу при программи- ровании процедуры поиска всех слов в заданном тексте. Хотя при этом понадобятся несложные дополнительные операции, такие, как определение ситуации, при которой дальнейший поиск не нужен (поскольку все слова строки просмотрены), можно утверждать, что в нашем распоряжении имеются все необходи- мые средства для решения этой и подобных задач. 9.3.3. Поиск в строке подстрок Поиск конкретной подстроки в заданном тексте является ти- пичной процедурой, реализуемой редактором текста. Такой по- иск может оказаться полезным и в других ситуациях, таких как
Обработка символьных данных 281 нахождение требуемого элемента в таблицах строк. В приводи- мом ниже примере рассматривается простая задача, решение которой связано с поиском в строках определенных подстрок. Д Пример 9.12 • Постановка задачи Исходные данные: целое число LENGTH, за которым сле- дует LENGTH слов. Каждое слово содержит не более 26 сим- волов. LENGTH < 101. Искомый результат: таблица отличных друг от друга слов, встречающихся в исходных данных, с указанием частоты их появления в этих исходных данных. Для решения этой задачи не нужно осуществлять поиск слов в исходном тексте, поскольку в нем слова уже разделены между собой. Главной процедурой, определяющей алгоритм решения, является поиск слова в таблице. Если такое слово уже имеется в таблице, то получает приращение содержимое счетчика час- тоты появления этого слова в тексте. Если слова еще нет в таб- лице, то его нужно туда поместить и установить значение содер- жимого данного счетчика, равным 1. Решение этой задачи можно было бы описать на языке ассемблера, используя рас- смотренные выше команды сравнения и пересылки строк сим- волов и осуществляя поиск определенных подстрок в тексте из- ложенным в предыдущем разделе способом. Однако существует более удобный способ реализации обеих этих процедур, заклю- чающийся в использовании имеющейся в системе VAX команды манипулирования символьными данными МАТСНС. Она имеет следующий формат: МАТСНС длина „искомой „ст роки, искомая„строка, длина_исходной„строки, исходная„строка Как обычно, операнды длина имеют значения целых чисел без знака, а операнды искомая_строка и исходная_строка являются адресами искомой и исходной строки. С помощью команды МАТСНС осуществляется поиск ука- занной в команде подстроки (искомой строки) в заданной строке (исходной строке). Если искомая строка найдена, биту7 признака результата присваивается значение 1, в противном случае — значение 0. При выполнении этой команды использу- ются четыре регистра с младшими номерами. В регистр R2 по- мещается число, равное количеству символов исходной строки, оставшихся непросмотренными после нахождения искомой стро- ки, или 0, если поиск завершается безрезультатно (искомая строка не обнаружена). В регистр R3 записывается адрес пер- вого символа исходной строки, следующего непосредственно за
282 Глава 9 последним символом искомой строки, если она была найдена, в противном случае (искомая строка не обнаружена) в R3 по- мещается адрес первого байта, расположенного вслед за по- следним символом исходной строки. Регистры R0 и R1 исполь- зуются во время выполнения команды, но в них не сохраняется какой-либо полезной информации. Теперь рассмотрим программирование решения задачи при- мера 9.12. • Алгоритм решения задачи на псевдокоде Ввести число, равное количеству слов в тексте, в область па мяти LENGTH FOR COUNT := 1 ТО LENGTH DO Ввести слово в область памяти WORD IF содержимое области WORD отсутствует в таблице TABLE THEN поместить содержимое WORD в TABLE ENDIF Увеличить на 1 содержимое счетчика числа появлений в тексте слова, находящегося в области WORD END-FOR Вывести на печать таблицу TABLE вместе с частотами появле ния слов в тексте Конец программы Хотя в этой задаче необходимо адресовать элементы мас- сива строк, необходимость в использовании команды INDEX отсутствует, поскольку поиск элемента массива по значению ин- декса не производится. • Программа на языке ассемблера ФОРМИРОВАНИЕ ТАБЛИЦЫ ЧАСТОТЫ ПОЯВЛЕНИЯ СЛОВ В ИСХОДНОМ ТЕКСТЕ ИСХОДНЫЕ ДАННЫЕ: ЦЕЛОЕ ЧИСЛО LENGTH, ЗА КОТОРЫМ СЛЕДУЕТ LENGTH СЛОВ; LENGTH < 101 ИСКОМЫЙ РЕЗУЛЬТАТ: ТАБЛИЦА ОТЛИЧАЮЩИХСЯ ДРУГ ОТ ДРУГА СЛОВ ИСХОДНОГО ТЕКСТА С УКАЗАНИЕМ ДЛЯ КАЖДОГО СЛОВА ЧАСТОТЫ ЕГО ПОЯВЛЕНИЯ В ТЕКСТЕ ; ОБЛАСТИ ПАМЯТИ ДЛЯ TABLE; .BYTE ~А/ /[2500] ; ТАБЛИЦЫ СЛОВ
Обработка символьных данных 283 TAB.LEN: .BLKL 1 ; ДЛИНЫ ТАБЛИЦЫ ; СЛОВ В БАЙТАХ \ TAB.ADDR: .ADDRESS TABLE ; АДРЕСА ТАБЛИЦЫ СЛОВ NUM-ENTRIES: .BLKL 1 ; КОЛИЧЕСТВА ЭЛЕМЕНТОВ WORD: LENGTH: ; В ТАБЛИЦЕ СЛОВ .BLKB 25 ; СЛОВА ИСХОДНОГО ТЕКСТА .BLKL 1 ; ДЛИНЫ ИСХОДНОГО МАССИВА ; СЛОВ COUNT: .BLKW 1 ; СЧЕТЧИКА ОПЕРАЦИЙ FREQ: ; ВВОДА-ВЫВОДА .BYTE 0 [100] : ЧАСТОТЫ ПОЯВЛЕНИЯ СЛОВ ; В ИСХОДНОМ ТЕКСТЕ .ENTRY INIT_IO CLRL CLRL PRINT_L READ-L ЕХ_9_12, 0 TAB-LEN NUM-ENTRIES "ЗАДАЙТЕ ЧИСЛО СЛОВ' LENGTH ; ДЛЯ COUNT:= 1 ДО LENGTH ВЫПОЛНЯТЬ В ЦИКЛЕ MOVL CMPL BLEQ BRW LOOP: # 1, COUNT COUNT, LENGTH LOOP OUT-LOOP MOVC5 PRINT_L READ_A # 0, WORD, # ~A/ /, # 25, WORD "'ВВЕДИТЕ ОЧЕРЕДНОЕ СЛОВО' WORD ; ЕСЛИ ТАБЛИЦА ПУСТА TSTL BNEQ TAB-LEN ELSE ; ТО ПОМЕСТИТЬ СЛОВО В ТАБЛИЦУ, УВЕЛИЧИТЬ ; НА 1 СОДЕРЖИМОЕ СЧЕТЧИКА ЧИСЛА ЭЛЕМЕНТОВ ; ТАБЛИЦЫ И ПРИСВОИТЬ СОДЕРЖИМОМУ ОБЛАСТИ ; FREQ ЗНАЧЕНИЕ, РАВНОЕ 1 MOVC3 ADDL2 MOVL MOVB BRW #25, WORD, TABLE #25, TAB_LEN #1, NUM-ENTRIES #1, freq ENDIF
£84 Глава 9 ;ИНАЧЕ ЕСЛИ СЛОВО В ТАБЛИЦЕ НЕ НАЙДЕНО МАТСНС #25, WORD, TAB.LEN, TABLE BEQL ITS-THERE ; TO ПОМЕСТИТЬ СЛОВО В ТАБЛИЦУ ; (ПО АДРЕСУ, УКАЗАННОМУ В РЕГИСТРЕ R3) MOVC3 #25, WORD, (R3) ADDL2 #25, TAB.LEN INCL NUM-ENTRIES ; КОНЕЦ ОПЕРАЦИИ «ЕСЛИ» ; УВЕЛИЧИТЬ НА 1 СОДЕРЖИМОЕ СЧЕТЧИКА ; ЧАСТОТЫ ПОЯВЛЕНИЯ СЛОВА (АДРЕС ; СЧЕТЧИКА = ((R3 - АДРЕС ТАБЛИЦЫ - 1 )/25)) 1TS-THERE: SUBL2 TAB.ADDR, R3 DECL R3 DIVL2 #25, R3 INCB FREQ[R3] • КОНЕЦ ОПЕРАЦИЙ «ЕСЛИ» (ЕСЛИ ТАБЛИЦА ПУСТА) ENDIF: AOBLEQ LENGTH, COUNT, LOOP ; КОНЕЦ ЦИКЛА «ДЛЯ» CUT-LOOP: PRINTL '-'ТАБЛИЦА ЧАСТОТЫ ПОЯВЛЕНИЯ СЛОВ' CLRL R7 • ДЛЯ COUNT := 1 ДО NUM-ENTRIES ВЫПОЛНЯТЬ В ЦИКЛЕ MOVL # 1, COUNT CMPL COUNT, NUM-ENTRIES BLEQ P.LOOP BRW OUT_P_LOOP P-LOOP: PRINT-A ', #25, @TAB_ADDR PRINT-B ', FREQ [R7] ADDL2 #25, TAB.ADDR INCL R7 AOBLEQ NUM-ENTRIES, COUNT, P_LOOP
Обработка символьных данных 285 ♦ КОНЕЦ ЦИКЛА «ДЛЯ» OUT_P_LOOP: $EXIT_S .END ЕХ_9_12 Эта программа приведена с целью демонстрации особенно- стей использования команды МАТСНС. Применение цикла FOR и индексирования для обращения к элементам массива позво- лило бы создать более эффективный машинный код для реше- ния данной задачи. Несколько команд системы VAX, предназначенных для об- работки символьных данных, не рассмотрены в этой главе. К ним относятся команды взаимного преобразования числовых данных и строк символов, описываемые в гл. 12. Выводы 1. При всех манипуляциях с символьными данными в систе- ме VAX для кодирования символов используется код ASCII. 2. Константы, записываемые в память в коде ASCII, могут быть сформированы с помощью директивы .ASCII или .ASCIC, которая вычисляет также и длину такой константы. 3. Константы, представляющие собой символьные данные, могут указываться в операндах в виде литералов путем заклю- чения их в символы-ограничители и записи перед ними знака и буквы А С А). 4. Команда СМРСЗ позволяет сравнивать между собой стро- ки символов одинаковой длины, а команда СМРС5 используется для сравнения строк различной длины. 5. Команда MOVC3 пересылает строку символов в область памяти, предназначенную для строки такого же размера. Команда MOVC5 пересылает строку символов в область памяти, размер которой не совпадает с размером пересылаемой строки. Символ-заполнитель используется для дополнения пересылае- мой строки до размера принимающей области памяти, если это необходимо. Лишние символы пересылаемой строки игнори- руются. 6. Команды LOCC и SKPC позволяют осуществлять про- смотр строки с целью обнаружения первого символа строки, совпадающего или не совпадающего с указанным в команде символом соответственно. 7. Команды SPANC и SCANC позволяют осуществлять про- смотр строки с целью поиска набора символов, задаваемых в команде.
286 Глава 9 8. Команда МАТСНС предоставляет возможность поиска в заданной исходной строке определенной подстроки, указанной В команде. Новые команды СМРСЗ МАТСНС MOVC5 SKPC СМРС5 MOVC3 SCANC SPANC LOOC Новые директивы .ASCII .ASCIC Новые способы записи операндов ~А Новые команды ввода-вывода PRINT_A READA Вопросы и упражнения 1. Чем отличаются действия, выполняемые директивами .ASCII и .ASCIC? 2. Опишите литералы, используемые для задания символь< ных констант. 3. Как используется регистр R0 при выполнении команды СМРСЗ? 4. Как используются регистры R0 и R2 при выполнении команды СМРС5? 5. Как используется регистр R1 при выполнении команды MOVC3? 6. Как воздействует команда MOVC5 на значение бита Z признака результата? 7. Как используется регистр R1 при выполнении команды LOCC? 8. Как воздействует команда SKPC на значение бита Z при- знака результата? 9. Дайте полное описание действий, выполняемых командой SCANC. 10. Как воздействует команда SPANC на значение бита Z признака результата? И. Как выполнение команды SCANC влияет на содержимое регистра R1?
Обработка символьных данных 287 12. Как выполнение команды МАТСНС влияет на содержи- мое регистра R2? 13. Как воздействует команда МАТСНС на значение бита Z признака результата? 14. При каких условиях для всех команд манипулирования строками символов биту Z признака результата присваивается значение 1? Напишите на языке ассемблера и выполните отладку про- грамм для решения следующих задач. 15. Исходные данные: пять строк текста. Искомый результат: количество строчных букв а и b в тексте. 16. Исходные данные: строка символов, которая может со- держать подстроку, ограниченную (с обоих концов) знаком «.» (точка), причем в тексте может быть либо две точки, либо ни одной. Искомый результат: подстрока, ограниченная точками, если она присутствует в тексте. 17. Исходные данные: ряд строк текста, завершающихся строкой, начинающейся пятью буквами Z. Исходный текст со- держит слова, представляющие собой строки букв, ограничен- ные пробелами. Искомый результат: список всех слов исходного текста, вы- водимых на печать столбцом одно слово под другим. 18. Исходные данные: несколько строк текста, завершаю- щихся строкой, начинающейся тремя точками. Исходный текст содержит слова, состоящие из букв, причем перед словом по- мещается либо пробел, либо кавычки («), а после слова —про- бел, точка, запятая или кавычки. Кроме того, слова могут на- чинаться с позиции первого символа текста и (или) кончаться в последней строке. Искомый результат: слова исходного текста, выводимые на печать столбцом. 19. Исходные данные: те же, что и в п. 16. Искомый результат: список отличающихся друг от друга слов исходного текста с указанием частоты их появления. 20. Исходные данные: те же, что и в п. 17. Искомый результат: тот же, что и в п. 18. 21. Исходные данные: ряд строк текста, состоящих из строч- ных слов, разделенных пробелами, последняя строка начинается тремя точками. Искомый результат: исходный текст, в котором везде слово «яблоко» заменено на слово «апельсин». 22. Исходные данные: те. же, что и в п. 20. Искомый результат: исходный текст, из которого удалены все слова «слива»; остающиеся после их удаления места не запол- няются пробелами, они удаляются.
288 Глава 9 23. Исходные данные: те же, что и в п. 20, за исключением того, что две дополнительные строки предшествуют всем осталь-» ным исходным данным. Каждая из этих двух дополнительных строк содержит одно слово. Искомый результат: исходный текст, в котором все слова, совпадающие со словом, указанным в первой дополнительной строке, заменены на слово, указанное во второй дополнительной строке. 24. Исходные данные: единственная строка текста, за кото- рой следуют два целых числа, помещенные во вторую строку. Искомый результат: текст исходной строки, представляющий собой подстроку, начинающуюся с позиции исходной строки, указанной первым числом, введенным во второй строке, и имею- щую длину, задаваемую вторым числом этой строки.
Глава 10 Подпрограммы Подпрограммы являются одним из наиболее важных средств программирования как на языке высокого уровня, так и на языке ассемблера. Это есть следствие по крайней мере двух основных причин. Во-первых, использование подпрограмм по- зволяет избежать повторной разработки и создания некоторых частей программы. Однажды написанная и прошедшая отладку подобная процедура может быть использована не только в дан- ной, но и во всех последующих программах столько раз, сколь- ко это необходимо. Текст подпрограммы не нуждается в по- вторной записи на бланке программирования (и последующих операциях), поскольку может храниться в той или иной запоми- нающей среде (в памяти на магнитном носителе). Во-вторых, и это наиболее важно, посредством подпрограмм возможна деком- позиция программ на отдельные части, логически самостоятель- ные и относительно небольшие, что удобно для манипуляций с ними. На практике большими программами можно оперировать только при условии их расчленения на сравнительно неболь- шие модули. Убедившись в важности роли подпрограмм, можно теперь перейти к рассмотрению их реализации средствами языка ас- семблера системы VAX, начав с описания стека и команд, вы- полняющих операции с его содержимым, поскольку стек ис- пользуется для установления связей между вызывающей и вы- зываемой программными единицами. 10.1. Операции со стеком Стек — это некоторая базовая структура данных, широко ис- пользуемая в вычислительной технике, начиная с операционных систем и кончая счетно-решающими устройствами. В рассмат- риваемом случае наиболее подходящим применением стека яв- ляется его использование для организации взаимосвязей про- грамм п вызываемых ими подпрограмм. Однако, прежде чем перейти к рассмотрению того, как создаются подпрограммы, необходимо ознакомиться с набором операций со стеком в си- стеме VAX. ю Зак. 483
290 Глава 10 Стек представляет собой последовательность однотипных ячеек памяти; по структуре он подобен одномерному массиву данных. Основное различие между стеком и одномерным мас- сивом в том, как осуществляется доступ к отдельным элементам (данным). Доступ к элементам массива произволен, т. е. к лю- бому элементу можно «обратиться» в любое время и в любом порядке. В противоположность этому доступ к элементам стека строго регламентирован. Инициализация работы со стеком пред- полагает отсутствие в нем данных. В таком случае принято го- ворить, что стек пуст. Данные могут быть загружены (добав- лены) в стек или изъяты из него только с одного его конца. Следовательно, содержимое стека увеличивается или умень- шается с одного, «активного» конца, получившего название вер- шины стека. Загрузка данных в стек подобна тому, как в кафетерии со- ставляются чистые подносы в соответствующий контейнер с пру- жинным механизмом подачи очередного подноса наверх. Чем больше подносов положено в контейнер, тем больший груз да- вит на пружины, прижимая их книзу. В результате этого верх- ний поднос расположен всегда на одной и той же высоте (по отношению к дну контейнера). Подобным же образом мож- но рассматривать стек данных в вычислительной машине: вер- шина стека занимает стационарную позицию, а его противопо- ложный конец перемещается вверх или вниз в зависимости от дополнительной загрузки данных в стек или их извлечения от- туда. Однако точная реализация на практике подобной модели стека в памяти машины оказалась бы крайне неэффективной. При каждой загрузке данных в стек или удалении их из него требовалось бы перемещение всех других элементов (данных) стека. Практически значительно эффективнее зафиксировать (сделать стационарной) позицию дна стека, а не его вершины. В системе VAX самый нижний элемент стека является первым элементом области памяти, предоставляемой для размещения стека. Вершину стека занимает так называемый указатель, ме- няющий свое значение (увеличивая его или уменьшая) при до- бавлении данных в стек или извлечении их оттуда. Программ- ные средства реализации такого принципа просты: для задания вершины стека используется переменная целого типа размером длинное слово, которой первоначально присваивается значение начального адреса стека. По соглашению, принятому в системе VAX, стек наращивает- ся «в сторону» уменьшающихся значений адресов памяти. Это означает, что указателю позиции вершины того или иного стека первоначально присваивается значение самого старшего адреса
Подпрограммы 291 области памяти, предоставляемой для организации данного стека. Операция загрузки в стек уменьшает значение указателя вершины стека на размер загружаемого элемента данных и за- тем помещает этот элемент по адресу, соответствующему новому значению указателя вершины стека. Операция извлечения из стека перемещает содержимое области памяти, адресуемое ука- зателем вершины стека, в определенное место и затем увеличи- вает значение указателя на размер элемента данных, удален- ного из стека. Операции загрузки и удаления длинных слов при- менительно к стеку показаны на рис. 10.1. Рис. 10.1. Операции по удалению одного числа из стека и загрузки в него другого. В языке ассемблера системы VAX эти операции могут быть весьма просто реализованы посредством косвенной адресации с автоувеличением и автоуменьшением адреса. Используем ре-* гистр в качестве указателя вершины стека и присвоим содер- жимому этого регистра в качестве начального значения адрес последнего элемента области памяти, предназначенной для раз- мещения стека. Тогда применение команды MOVx с автомати- ческим уменьшением содержимого регистра — указателя верши- ны стека, используемого в качестве второго операнда команды, позволит эффективно загрузить первый операнд в стек. Посред- ством команды MOVx с автоматическим увеличением содержи- мого регистра — указателя вершины стека, можно столь же эф- фективно удалить верхний элемент стека и поместить его по адресу, задаваемому вторым операндом команды. Рассмотрим следующий пример*
292 Глава 10 Л Пример 10.1. Операции с содержимым регистра — указателя стека STACK: .BLKL 100 MOVAL STACK+ 400, R6 MOVL # 42, - (R6) MOVL #426, ~(R6) MOVL (R6)+, VALUE Этот фрагмент программы начинается резервированием для сте- ка области памяти размером в 100 длинных слов, при этом эле- менты этой области «очищаются», т. е. их содержимому при- сваиваются нулевые значения. Затем посредством команды MOVAL в регистр R6 — указатель вершины стека — записы- вается адрес байта, следующего первым за концом области па- мяти, резервируемой для стека. Так реализуются исходные усло- вия организации стека. Первые две команды MOVL загружают в стек два числа: 42 и 426. Каждая подобная операция загрузки уменьшает на 4 зна- чение указателя вершины стека, всегда обеспечивая посредством этого указателя адресацию к элементу, расположенному в дан- ный момент на вершине стека. Последняя команда MOVL рассматриваемого фрагмента программы удаляет из стека число 426, расположенное на его вершине, и помещает его в область памяти, именуемую VALUE. При этом указатель вершины стека получает приращение и его значение становится адресом местоположения числа 42, заняв- шего теперь вершину стека. Хотя рассмотренный вариант реализации операций со сте- ком вполне работоспособен, большинство операций со стеком в языке ассемблера системы VAX «имеют дело» с определенным стеком и используют команды, приспособленные для манипу- ляций со стеком. В дальнейшем под термином «стек» пони- мается именно такой стек. Вычислительная система выделяет память для стека во вре- мя создания редактором связей выполняемого модуля данной программы. Указателем вершины стека является регистр R14, обычно сокращенно именуемый SP (Stack Pointer — указатель стека). Исходное (начальное) значение последнему присваи- вается перед выполнением программы. Следовательно, чтобы
П одпрограммы 293 воспользоваться стеком, достаточно только использовать SP в качестве его указателя; при этом нет необходимости заботиться ни о выделении памяти для стека, ни о присвоении указателю вершины стека начального значения. На применение стека на- кладывается только одно ограничение: все специализированные стековые команды оперируют длинными словами. Поскольку большинство данных, подлежащих хранению в стеке, представ- ляют собой адреса, указанное ограничение нельзя признать сколько-нибудь значительным. Для загрузки длинного слова в стек используется команда PUSHL, имеющая один операнд и функционирующая подобно команде MOVL, вторым операндом которой является — (SP). Операнд команды PUSHL задает данные размером длинное слово, подлежащие загрузке в стек. Например, PUSHL #12 уменьшает на 4 значение SP, а затем помещает десятичное число 42 размером длинное слово в стек. Команда POPL по своему назначению противоположна команде PUSHL. Она извлекает («выталкивает») из стека дан- ные размером длинное слово и помещает их по адресу, зада- ваемому ее операндом, после чего увеличивает значение SP на 4. Например, POPL VALUE удаляет из стека длинное слово, адресуемое указателем SP, помещает его в область памяти, именуемую VALUE, а затем добавляет число 4 к значению SP. В действительности система VAX не располагает для POPL соответствующей машинной командой. Когда в программе на языке ассемблера встречается строка вида "POPL операнд"* вычислительная система создает реализующую требуемые опе- рации команду "MOVL (SP) + , операнд". Но это не проти- воречит тому факту,что в списке команд языка ассемблера си- стемы VAX имеется команда PUSHL. Поскольку часто возникает необходимость записывать в стек адреса, система VAX располагает набором команд вида PUSH Ах для загрузки адресов соответствующих операндов в стек. Вместо условного обозначения х используется прописная буква В, W, L или Q, указывающая на загрузку в стек адреса байта, слова, длинного слова или двойного длинного слова со- ответственно. В любом случае при выполнении подобной коман- ды значение SP уменьшается на 4, а затем адрес операнда в виде 32-битовой величины помещается по адресу, содержаще- муся в SP. Прежде чем перейти к выполнению подпрограммы, рекомен- дуется сохранить содержимое регистров, используемых програм- мой, вызывающей данную подпрограмму. В противном случае будет потеряна информация, которую программа размещала в этих регистрах. Сохранить содержимое регистра означает зари- сать хранимую там информацию в память непосредственно печ
294 Глава 10 ред обращением к подпрограмме с последующим восстановле- нием этого содержимого перед возвратом управления вызываю- щей программе. Для упрощения этих операций система VAX предоставляет программисту специальную пару команд POPR и PUSHR, каждая из которых имеет операнд, по форме отлич- ный от рассмотренных до сих пор. Обобщенная форма этого операнда, именуемого маской регистров, имеет следующий вид: ~М {список регистров} В соответствии с этим операндом создается 16-битовая строка (слово), каждый бит которой соответствует одному из 16 ре- гистров. Биту каждого регистра, имя которого указывается в списке регистров операнда, присваивается значение 1. Все остальные биты маски имеют нулевые значения. При использо- вании такого операнда в команде POPR или PUSHR список ре- гистров может включать R0—R12, АР, FP и SP. Отметим, что в этом списке отсутствует (не допустим к применению) регистр PC (Program Counter — Счетчик Команд или сокращенно СК), а для регистра R12 возможно использование его альтернатив- ного наименования АР. Маска регистров, применяемая как опе- ранд команды POPR или PUSHR, должна быть представлена в виде литерала, а именно ей должен предшествовать знак =#=. В приводимом ниже примере содержимое указанных регист- ров сначала загружается в стек, а затем удаляется из него и помещается обратно в регистры. Д Пример 10.2. Сохранение и восстановление содержимого регистров PUSHR #~M<R2, R7, R8> POPR #~M<R2, R7, R8) Для корректного функционирования этой пары команд в вы- числительной системе должны быть приняты специальные меры. Чтобы команда POPR могла восстановить правильное значение содержимого соответствующих регистров, команда PUSHR должна загружать содержимое регистров в стек в одном по- рядке, а команда POPR извлекать его оттуда в противополож- ном. Команда PUSHR начинает загружать первым содержимое регистров с наибольшими номерами в маске (списке) регист- ров. Команда POPR извлекает из стека первым содержимое ре- гистров с наименьшими номерами в своей маске регистров. За- метим, что порядок записи номеров регистров в маске не играет при этом никакой роли. Например, следующие две команды
Подпрограммы 295 также решают задачу сохранения и последующего восстановле- ния содержимого регистров. Д Пример 10.3. Неупорядоченный список регистров в маске PUSHR #~M(R7, R3, R10> POPR #~M(R3, R7, RIO) 10.2. Простые подпрограммы В системе VAX рассмотрено несколько вариантов реализации подпрограмм. Простейшие по структуре подпрограммы получи- ли название субрутин (subroutine). Им присуще использование ограниченных по своим возможностям неформальных способов передачи параметров. Они не располагают средствами обработ- ки ошибок. Для передачи данных из субрутины и в нее применяются два глобально доступных «хранилища» информации — R0 и R1, которые, однако, часто используются вычислительной системой (например, командами, манипулирующими строками символов) и поэтому являются наименее безопасными местами долговре- менного хранения данных. Поэтому можно считать вполне есте- ственным выбор их для временного хранения информации, ко- торой обмениваются вызывающий и вызываемый программные модули. Для реализации подпрограммы любого вида необходим спо- соб передачи управления этой подпрограмме при обращении к ней и возврата управления вызывавшей программе после того, как подпрограмма выполнила свои функции. Вызвать субру- тину просто: можно воспользоваться командой BRW. Однако вернуться к вызывавшей программе несколько сложнее. По- скольку рекурсивное использование субрутин недопустимо, мож- но пересылать адрес возврата в субрутину при обращении к ней для хранения его где-либо, а затем заставлять субрутину адре- соваться к местоположению этого адреса при возврате управ- ления вызывавшей программе. Такое решение предполагает на- личие команды косвенной передачи управления. (Рекурсивные подпрограммы рассматриваются в разд. 5 данной главы.) Более гибкое решение достигается, однако, при использовании стека для хранения адреса возврата. В системе VAX предусмотрено несколько способов организации связи подпрограммы с вызы- вающими программными модулями. Для написания субрутин в распоряжение программиста предоставляются три различные команды записи адреса воз- врата на хранение в стек с последующим переходом по адресу
296 Глава 10 заданной субрутины. Благодаря этому в каждом конкретном случае можно выбрать простейшее решение. Команда BSBx загружает содержимое счетчика команд (СК) в стек, а затем передает управление по адресу, задаваемому ее операндом согласно режиму относительной адресации «сме- щением к СК» (в соответствии с которой действительное зна- чение этого адреса определяется как сумма значения операнда и содержимого счетчика команд, увеличенного на длину данной команды). В мнемонике (символическом обозначении кода опе- рации) данной команды вместо условного обозначения х долж- на использоваться латинская буква В или W, указывающая дли- ну смещения (определяемого операндом команды), которое подлежит добавлению к содержимому счетчика команд с целью получения фактического адреса. Например, BSBB SUB1 загру- жает содержимое СК в стек, а затем использует смещение дли- ной 1 байт для адресации к подпрограмме SUBI. Следует об- ратить внимание, что значение загружаемого в стек содержи- мого СК точно равно адресу возврата (адресу команды, сле- дующей за командой BSBB). Команда BSBB пригодна только для адресации к подпрограммам, удаленным от данной коман- ды на расстояние не более 127 байт. Это существенно ограни- чивает возможности применения данной команды, которую, как и команду АСВВ, следует отнести к категории нерекомендуемых к использованию. Ведь даже если при написании программы субрутина и находится в пределах адресного пространства раз- мером 1 байт, последующие изменения и дополнения текста программы часто выводят ее за эти пределы. Команда BSBW позволяет вызывать субрутины, удаленные от нее на расстояние до 32767 байт. Это, как правило, доста- точно в большинстве случаев. Когда же субрутина оказывается на расстоянии более 32767 байт, можно воспользоваться коман- дой JSB. Такие ситуации встречаются редко; их описание дано в гл. 15. Команда RSB используется для возврата управления вызы- вающей программе после завершения субрутиной выполнения своих функций. Это весьма необычная команда, у которой от- сутствуют операнды. Она просто извлекает из стека находя- щееся на его вершине длинное слово и помещает его в счетчик команд. Поскольку команда BSBx, передающая управление субрутине, загружает содержимое счетчика команд в стек, воз- врат в программу приводит к передаче управления команде, непосредственно следующей за BSBx. Такая передача управле- ния происходит только в том случае, когда субрутина не исполь- зовала стек или ей не удалось восстановить состояние стека, в котором он находился при входе в субрутину (имея адрес воз- врата на своей вершине).
Подпрограммы 297 Приводимые ниже примеры поясняют технику формирова- ния субрутин. Д Пример 10.4 • Постановка задачи Исходные данные: целое число Искомый результат: сообщение о том, является ли данное число простым Способ решения задачи: использование субрутины. Воспользуемся простым алгоритмом решения этой задачи: предпринимаются попытки разделить исходное число на 2, а затем на все нечетные целые числа от 3 до половины значения заданного числа; если исходное число — не простое, то найдется хотя бы один делитель, на который оно разделится без остатка. Отметим, что диапазон изменения делителя можно сократить, взяв вместо половины значения исходного числа его квадрат- ный корень. Однако делать этого не будем, поскольку здесь основное внимание уделяется языку ассемблера, а не численным методам математического анализа. • Алгоритм решения задачи на псевдокоде ПРИСВОИТЬ DIVISOR ЗНАЧЕНИЕ 3 ВЫЧИСЛИТЬ LIMIT КАК INPUT/2 (С ПРИСВОЕНИЕМ REMAINDER ЗНАЧЕНИЯ ОСТАТКА) WHILE (DIVISOR < LIMIT) AND (REMAINDER ( ) 0) DO РАЗДЕЛИТЬ INPUT HA DIVISOR (С ПРИСВОЕНИЕМ REMAINDER ЗНАЧЕНИЯ ОСТАТКА) ПРИБАВИТЬ 2 К DIVISOR END-DO IF REMAINDER ( ) 0 THEN ПРИСВОИТЬ RESULT ЗНАЧЕНИЕ 1 ELSE ПРИСВОИТЬ RESULT ЗНАЧЕНИЕ 0 ENDIF КОНЕЦ ПРОГРАММЫ Наиболее примечательным в данном алгоритме является ис- пользование так называемого составного условия: в операторе WHILE два отношения связаны символом логической операции AND (И). Программирование на языке ассемблера такого усло- вия не столь просто, как это может показаться на первый взгляд. Для этого необходимо воспользоваться логической ин- версией составного условия. Логической инверсией условия, со- ставленного из двух отношений, связанных операцией AND, являются инверсии этих отношений, связанные логической опе- рацией OR (ИЛИ). Например, логической инверсией (А > В) AND(C^D) является (А B)OR(C > D). При использова-
298 Глава 10 нии первого условия в операторе WHILE соответствующая запись на языке ассемблера (для случая переменных размером длинное слово) имела бы следующий вид: CMPL А, В BLEQ OUT_LOOP CMPL С, D BGTR OUT_LOOP Логической инверсией условия, составленного из двух от- ношений, связанных операцией OR (ИЛИ), являются инверсии двух отношений, связанные операцией AND. Программирование на языке ассемблера такого условия предполагает каждый раз проверку выполнения обоих отношений. Например, логиче- ской инверсией условия (А > B)OR(C D) является условие (А В) AND (С > D). Первое условие на языке ассемблера принимает следующий вид: CMPL А, В BLEQ SECOND BRW SKIP SECOND: CMPL C, D BGTR OUT_LOOP SKIP: Этот фрагмент программы не столь прост и компактен, как в случае использования составного условия с логической опера- цией AND. Начинающему программисту рекомендуется хорошо усвоить данный факт. Инвертирование логических выражений, содержащих операции OR и AND, является прямым следствием двух фундаментальных законов булевой алгебры, известных под названием теоремы Де-Моргана. Необходимо сделать еще одно замечание. При использова- нии составного условия для управления циклом типа WHILE иногда нужно знать, какие значения переменных вызывают вы- ход из цикла. Это можно осуществить, используя оператор IF после цикла. В алгоритме решения задачи примера 10.4 на псев- докоде результату присваивается то или иное значение в зави- симости от того, выполняется ли в цикле составное условие или его инверсия. Написанная на языке ассемблера субрутина, решающая за- дачу примера 10.4, использует для операций деления команду EDIV потому, что более короткие версии команды деления не сохраняют остатка. Ниже приводится текст небольшой програм-
Подпрограммы 296 мы, в которую встроена указанная субрутина для проверки ее работоспособности. • Программа на языке ассемблера ; ПРОГРАММА. ОПРЕДЕЛЯЮЩАЯ, ЯВЛЯЕТСЯ ЛИ ЦЕЛОЕ ЧИСЛО ; ПРОСТЫМ ; ИСХОДНЫЕ ДАННЫЕ: ЦЕЛОЕ ПОЛОЖИТЕЛЬНОЕ ЧИСЛО ; ИСКОМЫЙ РЕЗУЛЬТАТ: СООБЩЕНИЕ О ТОМ, ЯВЛЯЕТСЯ ЛИ : ЧИСЛО ПРОСТЫМ : СПОСОБ РЕШЕНИЯ: ПОСРЕДСТВОМ ПОДПРОГРАММЫ, ; ВЫПОЛНЯЮЩЕЙ ДЕЛЕНИЕ НА НЕЧЕТНЫЕ ;ЧИСЛА ; ОБЛАСТЬ ПАМЯТИ ДЛЯ ДАННЫХ ОСНОВНОЙ ПРОГРАММЫ .PSECT EXAMPLE, LONG VALUE: .BLKL 1; VALUE-ИМЯ ОБЛАСТИ ДЛЯ РАЗМЕЩЕНИЯ ; ИСХОДНОГО ЧИСЛА /подпрограмма prime ; ИСХОДНЫЕ ДАННЫЕ: ПОЛОЖИТЕЛЬНОЕ ЦЕЛОЕ ЧИСЛО ; В РЕГИСТРЕ R1 ; ИСКОМЫЙ РЕЗУЛЬТАТ: ЕСЛИ ЧИСЛО - ПРОСТОЕ, ; ТО RO = 1, ИНАЧЕ R0 = О ; СПОСОБ РЕШЕНИЯ: ДЕЛЕНИЕ ИСХОДНОГО ЧИСЛА НА 2 И ВСЕ ; НЕЧЕТНЫЕ ЧИСЛА, КОТОРЫЕ I МЕНЬШЕ ПОЛОВИНЫ ИСХОДНОГО ЧИСЛА (VALUE) ;PRIME: • ПРИСВОИТЬ ДЕЛИТЕЛЮ (DIVISOR) ЗНАЧЕНИЕ, РАВНОЕ 3 MOVL #3, DIVISOR ; ВЫЧИСЛИТЬ ПРЕДЕЛ (LIMIT) ЗНАЧЕНИИ ДЕЛИТЕЛЯ ПУТЕМ ; ДЕЛЕНИЯ ИСХОДНОГО ЧИСЛА НА 2 CLRL DIVIDEND+ 4 MOVL Rl, DIVIDEND EDIV #2, DIVIDEND, LIMIT, REMAINDER ; ПОКА DIVISOR < LIMIT И REMAINDER (ОСТАТОК) БОЛЬШЕ ; ИЛИ МЕНЬШЕ НУЛЯ ВЫПОЛНЯТЬ В ЦИКЛЕ LOOP:
300 Глава 10 CMPL DIVISOR, LIMIT BGEQ OUT-LOOP TSTL REMAINDER BEQG OUT-LOOP ;РАЗДЕЛИТЬ ИСХОДНОЕ ЧИСЛО НА ДЕЛИТЕЛЬ EDIV DIVISOR, DIVIDEND, QUOTIENT, REMAINDER ; ДОБАВИТЬ 2 К ДЕЛИТЕЛЮ ADDL2 #2, DIVISOR BRW LOOP ; КОНЕЦ ЦИКЛА «ПОКА» OUT-LOOP: ; ЕСЛИ ОСТАТОК БОЛЬШЕ ИЛИ МЕНЬШЕ НУЛЯ TSTL REMAINDER BEQL ELSE ; ТО ПРИСВОИТЬ RESULT (РЕЗУЛЬТАТУ) ЗНАЧЕНИЕ 1 MOVL # 1, R0 BRW ENDIF ; ИНАЧЕ ПРИСВОИТЬ RESULT ЗНАЧЕНИЕ 0 ELSE: CLRL RO • КОНЕЦ ОПЕРАЦИИ «ЕСЛИ» ENDIF • ВОЗВРАТ В ВЫЗЫВАЮЩИЙ ПРОГРАММНЫЙ МОДУЛЬ RSB • ОБЛАСТЬ ПАМЯТИ ДЛЯ ДАННЫХ ПОДПРОГРАММЫ DIVISOR: .BLKL 1 DIVIDEND: .BLKQ 1 LIMIT: .BLKL 1
П сопрограммы 301 REMAINDER: .BLKL 1 QUOTIENT: .BLKL 1 ; НАЧАЛО ОСНОВНОЙ ПРОГРАММЫ .ENTRY ЕХ_10_4, 0 INIT_IO PRINT-L "'ВВЕДИТЕ В МАШИНУ ЧИСЛО, ПОДЛЕЖАЩЕЕ ПРОВЕРКЕ' READ-L VALUE ; ВЫЗВАТЬ ПОДПРОГРАММУ PRIME MOVL VALUE, Rl BSBW PRIME ; ЕСЛИ РЕЗУЛЬТАТ (RO) = 1 CMPL RO, # 1 BNEQ ELSE2 TO VALUE - ПРОСТОЕ ЧИСЛО PRINT-L "'ИСХОДНОЕ ЧИСЛО ЯВЛЯЕТСЯ ПРОСТЫМ' BRW ENDIF2 ; ИНАЧЕ VALUE - НЕ ПРОСТОЕ ЧИСЛО ELSE2: PRINT_L "'ИСХОДНОЕ ЧИСЛО НЕ ЯВЛЯЕТСЯ ПРОСТЫМ' ; КОНЕЦ ОПЕРАЦИИ «ЕСЛИ» ENDIF2: $EXIT_S .END EX-10-4 В данном разделе описана и использована для решения за- дачи примера 10.4 простейшая форма подпрограммы — субру- тина. Ее возможности весьма ограниченны. Значительные огра- ничения накладываются на количество передаваемых парамет- ров. Примитивен механизм ее вызова, не допускающий рекур- сивного обращения к этой подпрограмме. Невозможен также вызов подпрограммы этого типа из программ, написанных на других языках программирования.
302 Глава 10 10.3. Передача фактических параметров через общий список формальных параметров В системе VAX имеются два способа передачи фактических па- раметров и взаимосвязи между подпрограммами, использующие стандартный интерфейс, который применяется между подпро- граммами этой системы. Взаимосвязанные подобным образом подпрограммы получили наименование процедур. Один из упомянутых выше способов взаимосвязи процедур использует для этих целей так называемый общий список па- раметров, что, однако, делает его наименее общим способом передачи параметров и взаимосвязи подпрограмм. Согласно этому способу, фактические параметры сгруппированы в неко- тором блоке памяти, адрес которого передается вызываемой процедуре. Но прежде чем перейти к детальному описанию об- щего списка параметров, необходимо ознакомиться со способа- ми передачи фактических параметров, именуемыми вызов по значению, вызов по имени и вызов по дескриптору. Вызов по значению предполагает передачу вызываемому программному модулю фактического значения параметра. Та- кой способ базируется на односторонней связи с вызываемым программным модулем путем передачи ему данных. Этот мо- дуль не может вернуть данные через параметр, переданный ему таким способом. В языке Паскаль вызов по значению является способом передачи параметров, принятым по умолчанию. Вызов по имени базируется на принципе передачи вызывае- мому программному модулю адреса фактического параметра. Это предполагает двухсторонний обмен данными между вызы- вающим и вызываемым программными модулями. Поскольку вызываемый модуль получает адрес, у него появляется возмож- ность не только взять данные, расположенные по указанному адресу, но и поместить туда новые данные. В языке Паскаль для задания вызова по имени необходимо использовать перед формальными параметрами ключевое слово VAR. В языке Фор- тран вызов по имени является стандартным способом передачи параметров. В языках программирования, используемых системой VAX, иногда для передачи параметров вызываемой процедуре при- меняется так называемый вызов по дескриптору. Вызываемая процедура получает описание местоположения необходимых ей данных с указанием их размера, типа и структуры. Обычно та- ким способом передается информация о строках симво- лов, Теперь перейдем к детальному рассмотрению передачи фак- тических параметров через общий список параметров. Исполь- зуемая для этих целей команда CALLG, которая вызывает про-
Подпрограммы 303 цедуру, имеет следующий вид: CALLG адрес-списка-параметров, ядрес-процедуры Чтобы стало понятным функционирование этой команды, необ- ходимо ознакомиться с приводимой ниже структурой общего списка параметров. Количество параметров в списке задается расположенным в его первой позиции байтом — числом без знака. Остальные три бай- та первого длинного слова должны содержать нули. Каждое по- следующее длинное слово предназначено для адреса фактиче- ского параметра при вызове по имени или для самого параметра при вызове по значению; причем информацией может быть за- нято все длинное слово или только часть его. Например, если необходимо передать адрес массива по имени LIST, а также указать его длину, то структура списка параметров принимает следующий вид: ARG-LIST: .LONG 2 ; КОЛИЧЕСТВО ПАРАМЕТРОВ .ADDRESS LIST ; АДРЕС МАССИВА LEN: .BLKL 1 ; ЗНАЧЕНИЕ ДЛИНЫ МАССИВА Теперь к процедуре, именуемой SORT, можно обратиться, ис- пользуя следующий фрагмент программы: MOVL LENGTH, LEN CALLG ARG.LIST, SORT Отметим, что значение переменной LENGTH, указывающее ко- личество элементов в массиве LIST, записывается в список па- раметров непосредственно перед использованием команды CALLG. Альтернативным решением было бы использование од-
304 Глава 10 ного длинного слова в списке параметров специально для зна- чения переменной. Следует помнить, что каждый из параметров в списке па- раметров, включая и указатель количества параметров, дол- жен быть длинным словом, несмотря на использование только первого байта этого длинного слова для представления факти- ческого параметра. Заметим также, что, если при других вы- зовах процедуры SORT требуется использовать другие пара- метры (например, сортировке подлежит другой массив), необ ходимо либо создать и использовать другой список параметров, либо перед каждым обращением к процедуре модифицировать значения в первом списке. При выполнении команды CALLG значения нескольких дан- ных загружаются в стек. Область памяти, занимаемая стеком, содержащим эти данные, называется блок вызова. Поскольку для функционирования большинства процедур требуется исполь- зование помимо R0 и R1 и других регистров, был разработан специальный способ сохранения содержимого регистров. Вместо того чтобы при вызове процедуры возлагать на нее обязанно- сти по загрузке содержимого регистров в стек, а при возврате из процедуры извлекать их содержимое из стека, в системе VAX предусмотрено выполнение этих действий неявным образом командами, обеспечивающими взаимосвязь вызывающего и вы- зываемого программных модулей. Первая строка текста процедуры содержит директиву .ENTRY, которая включает как имя этой процедуры, так и маску входа в нее, указывающую регистры, содержимое которых под- лежит сохранению в стеке, а также биты разрешения фиксации переполнения десятичной и целочисленной арифметики (DV и IV соответственно), которым должны быть присвоены значе- ния 1 на время функционирования процедуры. В качестве вто- рого операнда директивы .ENTRY используется ~М — символ операции создания 16-битовой маски входа. Например, первая строка текста процедуры SORT, использующей R5, R6, R7, R8 и присваивающей значение 1 биту фиксации целочисленного пе- реполнения, могла бы иметь следующий вид: .ENTRY SORT, <IV, R5, R6, R7 R8> В этом случае команда CALLG извлекает слово, созданное в соответствии с символом ~М, и загружает в стек содержимое перечисленных регистров, начиная с регистра с самым старшим номером. Отметим, что некоторые регистры не могут быть ука- заны в маске, а именно: RO, R1, АР, FP, SP и PC. Другая информация, записываемая командой CALLG в блок вызова на хранение, размещается в нем перед содержимым ре-
Подпрограммы 305 гистров. Блок вызова имеет следующую обобщенную форму: Адрес подпрограммы обработки особых ситуаций SPA S O Маска PSW 00000 Сохраняемое содержимое АР Сохраняемое содержимое FP Сохраняемое содержимое PC Сохраняемое содержимое регистров Первое длинное слово блока вызова содержит адрес подпро- граммы обработки особых ситуаций. Команда CALLG записы- вает в это слово нуль. Система передает управление по ука- занному адресу при возникновении особой ситуации в процессе выполнения команд вызванной процедуры. Если нет необходи- мости в специальных действиях в ответ на возникновение осо- бой ситуации, содержимое упомянутого слова остается равным нулю. В противном случае процедура помещает в это длинное слово адрес той группы машинных команд, которые подлежат выполнению при возникновении особой ситуации. Второе длинное слово блока вызова содержит различные информационные биты. Двухбитовое поле SPA используется си- стемой, а не программистом, и поэтому здесь рассматриваться не будет. Однобитовое поле S указывает, какой из вызовов имеет место — CALLG или CALLS. (Об этом более детально речь идет в следующем разделе.) Однобитовое поле, следующее за полем S, и 5 самых младших двоичных разрядов этого длин- ного слова не используются и всегда содержат нули. Поле ма- ски предназначено для хранения битов 0—11 маски входа, опи- сываемой первым словом вызываемого программного модуля. Правое слово (младшее по значимости в длинном слове) пред- назначено для хранения битов 5—15 слова состояния програм- мы (PSW), каковыми они являются к моменту начала выпол- нения команды CALLG. Третье, четвертое и пятое длинные слова блока вызова ис- пользуются для хранения содержимого регистра АР, FP и PC соответственно. За содержимым PC располагается содержимое регистров, указанных в маске входа. Поскольку стек «растет» в сторону уменьшающихся значений адресов, команды загрузки стека, создающие блок вызова, следуют в порядке, обратном соответствующему содержимому этого блока.
306 Глава 10 Теперь все необходимые действия команды CALLG можно описать в терминах псевдокода следующим образом: Извлечь маску входа из второго операнда команды CALLG; Загрузить содержимое всех регистров, указанных в маске входа (начиная с регистра с наибольшим номером); Загрузить содержимое регистров PC, FP, АР; Загрузить длинное слово, состоящее из SPA, S=0 (озна- чающее, что имеет место команда CALLG) (одиночный бит), битов 0—11 маски входа, битов 5—15 PSW, (пять битов); Загрузить равное нулю длинное слово (адрес подпрограммы обработки особых ситуаций); Установить FP в SP; Очистить двоичные разряды признака результата; Установить биты разрешения фиксации переполнения в со- ответствии с маской входа; Очистить двоичный разряд FU слова состояния программы (PSW); Присвоить счетчику команд значение адреса, задаваемого вторым операндом CALLG, увеличенное на 2. Наконец, можно перейти к рассмотрению того, как пишется процедура. Прежде всего необходимо выяснить, как осуществ- ляется адресация к параметрам. Регистр АР содержит адрес общего списка параметров, по- этому к каждому параметру можно адресоваться суммой неко- торого постоянного смещения и значения содержимого АР, кото- рое используется как косвенный адрес. В процессе выполнения процедуры местоположение количества • переданных фактиче- ских параметров определяется как (АР), местоположение пер- вого параметра — как 4 (АР), второго параметра — как 8 (АР) ц т. д. Используя перечисленные выражения как операнды, мож- но адресоваться к параметрам, вызываемым по значению. Для этого необходимо только перед каждым выражением поставить символ косвенной адресации @, придающий указанным выраже- ниям смысл двухуровневой косвенной адресации. С целью восстановления в системе состояния, предшество- вавшего переходу к вызываемой процедуре, и для передачи управления команде, следующей за CALLG, нужно воспользо- ваться командой RET, не имеющей операндов. Она удаляет блок вызова целиком, восстанавливает содержимое всех регист- ров, подлежавших сохранению, и передает управление команде, непосредственно расположенной за CALLG. Теперь все подготовлено для написания процедуры и про* верки ее работоспособности под действием команды CALLGe
Подпрограммы 307 Л Пример 10.5 • Постановка задачи Исходные данные*, целое число LENGTH, за которым следует LENGTH целых чисел (LENGTH <101). Искомый результат', последовательность исходных целых чи- сел, расположенных в порядке убывания их значений. Способ решения задачи', использование процедуры сортиров- ки обменом Алгоритм решения этой задачи подобен алгоритму сорти- ровки строки символов, описанному в гл. 9. • Программа на языке ассемблера ; ПРОГРАММА СОРТИРОВКИ МАССИВА ЦЕЛЫХ ЧИСЕЛ ; ИСХОДНЫЕ ДАННЫЕ 1) ЗНАЧЕНИЕ ПЕРЕМЕННОЙ ЦЕЛОГО ТИПА ; LENGTH (КОЛИЧЕСТВО ЭЛЕМЕНТОВ МАССИВА ЦЕЛЫХ ЧИСЕЛ) ; 2) LENGTH ЦЕЛЫХ ЧИСЕЛ; LENGTH < 101 ; ИСКОМЫЙ РЕЗУЛЬТАТ: ПОСЛЕДОВАТЕЛЬНОСТЬ ИСХОДНЫХ ; ЦЕЛЫХ ЧИСЕЛ В ПОРЯДКЕ УБЫВАНИЯ ; ИХ ЗНАЧЕНИЙ ; СПОСОБ РЕШЕНИЯ ЗАДАЧИ: ПРОЦЕДУРА, ВЫПОЛНЯЮЩАЯ ; ’ СОРТИРОВКУ ОБМЕНОМ ОБЛАСТЬ ПАМЯТИ ДЛЯ ДАННЫХ ОСНОВНОЙ ПРОГРАММЫ .PSECT EXAMPLE, LONG LIST: .BLKL 100 ; ИСХОДНЫЕ ДАННЫЕ LENGTH: .BLKL 1 ; КОЛИЧЕСТВО ИСХОДНЫХ ЧИСЕЛ ; (ЭЛЕМЕНТОВ МАССИВА) LIMIT; .BLKL 1 ; ПРЕДЕЛ ЦИКЛОВ ВВОДА/ВЫВОДА СПИСОК ФОРМАЛЬНЫХ ПАРАМЕТРОВ ДЛЯ ПОДПРОГРАММЫ СОРТИРОВКИ ARG-LIST: .LONG 2 ; КОЛИЧЕСТВО ПАРАМЕТРОВ .ADDRESS LIST ; АДРЕС МАССИВА LEN: .BLKL 1 ; ОБЛАСТЬ ДЛЯ ЗНАЧЕНИЯ ; КОЛИЧЕСТВА ЭЛЕМЕНТОВ ; В МАССИВЕ ; ПОДПРОГРАММА СОРТИРОВКИ (SORT) .ENTRY SORT, ~M(R7, R8) ARRAY = 4 ARRAY_LEN = 8
308 Глава 10 ; ПРИСВОИТЬ TOP-LIMIT ЗНАЧЕНИЕ LENGTH-2, ; А ВОТ-LIMIT ЗНАЧЕНИЕ LENGTH-1 SUBL3 #2, ARRAY-LEN(AP), TOP-LIMIT SUBL3 # 1, ARRAY-LEN(AP), BOT_LIMIT • ДЛЯ TOP-REG := 0 ДО TOP-LIMIT ВЫПОЛНЯТЬ В ЦИКЛЕ CLRL R7 CMPL R7, TOP-LIMIT BLEQ OUTER-LOOP BRW OUT_OUTER_LOOP OUTER-LOOP: ; ПРИСВОИТЬ BOT-START ЗНАЧЕНИЕ TOP-REG 4-1 ADDL3 # 1, R7, BOT-START ; ДЛЯ BOT-REG := BOT-START ДО BOT_LIMIT ВЫПОЛНЯТЬ В ЦИКЛЕ MOVL BOT-START, R8 IN-LOOP: ; ЕСЛИ ARRAY[TOP_REG] > ARRAY[BOT_REG] CMPL 6ARRAY(AP)[R7], 0ARRAY(AP)[R8] BGEQ ENDIF • ТОГДА ПОМЕНЯТЬ ИХ МЕСТАМИ MOVL @ARRAY(AP)[R7], - (SP) MOVL 6ARRAY(AP)[R8], 6ARRAY(AP)[R7] MOVL (SP) Ч-, eARRAY(AP)[R8] • КОНЕЦ ОПЕРАЦИЙ «ЕСЛИ» ENDIF: AOBLEQ BOT_LIMIT, R8, IN-LOOP ; КОНЕЦ ЦИКЛА (FOR BOT-REG- BOT-START) ’ AOBLEQ TOP-LIMIT, R7, OUTER-LOOP ; КОНЕЦ ЦИКЛА (ДЛЯ TOP-REG :=0) ; ВОЗВРАТ В ВЫЗЫВАЮЩИЙ ПРОГРАММНЫЙ МОДУЛЬ
Подпрограммы 309 OUT_OUTER_LOOP: RET ’ ОБЛАСТЬ ПАМЯТИ ДЛЯ ДАННЫХ ПОДПРОГРАММЫ СОРТИРОВКИ » TOP-LIMIT: .BLKL 1 ; ПРЕДЕЛ ДЛЯ TOP.REG BOT-START: .BLKL 1 ; НАЧАЛЬНОЕ ЗНАЧЕНИЕ ДЛЯ BOT.REG BOT-LIMIT: .BLKL 1 ; ПРЕДЕЛ ДЛЯ BOT.REG • НАЧАЛО ОСНОВНОЙ ПРОГРАММЫ .ENTRY ЕХ_10_5, 0 INIT-IO READ-L LENGTH ; ВЫЧИСЛЕНИЕ ЗНАЧЕНИЯ ПРЕДЕЛА ДЛЯ ЦИКЛОВ ; ВВОДА/ВЫВОДА SUBL3 # 1, LENGTH, LIMIT ; ДЛЯ REG:=0 ДО LIMIT ВЫПОЛНЯТЬ В ЦИКЛЕ CLRL R7 CMPL R7, LIMIT BLEQ READ-LOOP BRW OUT_READ_LOOP READ-LOOP: READ-L LIST[R7] AOBLEQ LIMIT, R7, READ-LOOP ; КОНЕЦ ЦИКЛА ; ДАННЫЕ ПОДПРОГРАММЫ СОРТИРОВКИ OUT_READ_LOOP: MOVL LENGTH, LEN CALLG ARG-LIST, SORT PRINT.L '''УПОРЯДОЧЕННАЯ ПОСЛЕДОВАТЕЛЬНОСТЬ' PRJNT.L ' ; ДЛЯ REG:=0 ДО LIMIT ВЫПОЛНЯТЬ В ЦИКЛЕ CLRL R7 CMPL R7, LIMIT BLEQ PRINT-LOOP BRW OUT_PRINT_LOOP PRINT-LOOP: PRINT.L ', LIST[R7j
310 Глава 10 AOBLEQ LIMIT, R7, PRINT-LOOP ; КОНЕЦ ЦИКЛА ;OUT-PRINT_LOOP: $EXIT-S .END EX-10-5 Некоторые особенности данной программы заслуживают вни- мания. Во-первых, запись значения длины массива в список па- раметров осуществляется непосредственно перед вызовом про- цедуры, хотя можно было бы иметь постоянно этот фактический параметр в списке. В данном конкретном случае это сделало бы программу более короткой, однако при необходимости сорти- ровки двух различных массивов постоянное хранение этого па- раметра в списке недопустимо: при записи длины второго мас- сива, подлежащего сортировке, значение длины первого массива было бы стерто. Во-вторых, поскольку использование элементов массива в процедуре влечет за собой многократное использова- ние адреса массива, последний (с целью сокращения размера операндов команд и времени их выполнения) можно было бы за- писать в регистр, что позволило бы перейти от двухуровневой косвенной адресации к одноуровневой. Команда MOVL AR- RAY (АР), R9 пересылала бы адрес массива в регистр R9, кото- рый затем мог бы быть использованным, например в команде CMPL (R9) [R7], (R9)[R8] Вызов процедуры посредством команды CALLG имеет не- сколько недостатков. Один из них вызван необходимостью раз- мещения параметров в программе не там, где находится коман- да CALLG, а в отдельной области. Это неудобно при чтении текста программы: найдя команду CALLG, нужно искать в тек- сте программы соответствующие этой команде параметры. Дру- гим недостатком является невозможность использования CALLG с целью рекурсивных обращений к подпрограммам. К достоин- ствам вызова посредством CALLG следует отнести высокую эф- фективность организации взаимосвязи вызывающего и вызывае- мого программных модулей. 10.4. Передача фактических параметров через стек В системе VAX средством вызова процедур, альтернативным CALLG, является CALLS. Вместо того, чтобы помещать факти- ческие параметры в блок памяти и передавать адрес этого бло- ка, можно посредством команды CALLS поместить параметры в стек, а количество этих параметров передать в качестве one-i
Подпрограммы 311 ранда. Обобщенная форма команды CALLS имеет следующий вид: CALLS количество-Параметров, адрес-Процедуры Функционирование CALLS подобно функционированию CALLG. Часть стека, выполняющая роль блока вызова, отли- чается лишь тем, что однобитовое поле содержит не 0, а 1 (ука- зывающую на то, что имеет место команда CALLS, а не CALLG). Выполнение команды CALLS сводится к загрузке фактиче- ских параметров в стек: сначала эта команда загружает в стек значение своего первого операнда — количество параметров, за- тем, подобно команде CALLG, она строит в стеке блок вызова и, наконец, устанавливает регистр АР таким образом, что он «указывает» на местоположение длинного слова, представляю- щего собой количество фактических параметров в стеке. В ре- зультате область памяти, занимаемая стеком, выглядит подобно общему списку параметров, используемому командой CALLG. Единственным существенным отличием между вызовами про- цедуры с помощью CALLS и CALLG является действие команды RET. При вызове процедуры с помощью CALLS команда RET должна удалить параметры из стека прежде, чем управление будет возвращено вызывавшему программному модулю. О том, когда это необходимо выполнить, команду RET информирует со- держимое однобитового поля S в блоке вызова. Например, команду CALLS можно использовать для вызова процедуры SORT (разд. 10.3). Для этих целей пригодна следую- щая последовательность команд: PUSHL LENGTH PUSHAL LIST CALLS #2, SORT Отметим обратный порядок следования параметров. Поскольку стек «растет» в направлении уменьшающихся значений адресов, а процедура адресуется к параметрам, как если бы они распо- лагались в памяти в порядке возрастающих значений адресного пространства, вызывающий программный модуль должен загру- жать параметры в стек в обратном порядке. В процедуре SORT регистр АР указывает на количество параметров, местоположе- ние адреса массива определяется, как АР + 4, а местоположе- ние длины массива, как АР + 8. Это справедливо независимо от того, вызывается ли эта процедура командой CALLG или коман- дой CALLS. В приведенном примере посредством PUSHL осу- ществляется вызов с передачей параметров по значению, а по- средством PUSHAx— вызов с передачей параметров по имени.
312 Глава 10 В некоторых языках программирования (например, в языке Паскаль) возможно рекурсивное обращение к подпрограммам, и поэтому в них для передачи параметров используется стек. В системе VAX все обращения к процедурам на языке Паскаль реализуются с помощью команды CALLS. Другой отличительной характеристикой рекурсивных про- цедур является требование динамического выделения локальной памяти при каждом обращении к процедуре. Процедура SORT не требует рекурсивного обращения к себе, и поэтому вполне приемлемым решением является использование для хранения данных этой процедуры блока памяти, примыкающего к ее кон- цу. Однако рекурсивно вызываемые процедуры помимо способно- сти динамически выделять локальную память должны допускать выбор локальных областей памяти из стека. Напомним, что в поле FP находится адрес адреса подпро- граммы обработки особых ситуаций. В то же самое время это поле в стеке является его последним длинным словом. Поэтому посредством содержимого поля FP и отрицательных смещений можно адресоваться к локальным областям памяти в стеке. Практически это реализуется вычитанием некоторого числа (рав- ного требуемому количеству байтов) из содержимого SP. На- пример, для процедуры по имени FINDER нужно четыре локаль- ные переменные: два длинные слова, именуемые МАХ и MIN, а также два слова для целых величин COUNT и LIMIT. Приво- димый ниже фрагмент программы на языке ассемблера решает эту задачу. Л Пример 10.6. Динамическое выделение памяти .ENTRY FINDER, ~М(...) МАХ = — 4 MIN = -8 COUNT = — 10 LIMIT = ~ 12 ADDL2 # LIMIT, SP Теперь можно адресоваться к четырем локальным перемен- ным следующим образом: MAX(FP), MIN(FP), COUNT(FP) и LIMIT(FP) При каждом обращении к процедуре FINDER положение че- тырех локальных переменных в стеке будет определено. Отме- тим, что при выделении памяти для этих четырех локальных пе- ременных содержимое FP не изменялось. Начало блока вызова отыскивается с помощью команды RET, поэтому последняя ав- томатически аннулирует всякое распределение локальной па-
Подпрограммы 313 мяти, выполненное для вызывавшейся процедуры (при условии, что выделение локальных областей памяти и адресация к ним выполнялись точно так, как это рассмотрено выше). Любая про- цедура на языке ассемблера, выделяющая локальную память из стека, может обращаться к самой себе посредством команды CALLS. Отметим, что, используя команду вычитания для изменения содержимого SP, можно перемещать SP по всей динамически выделяемой памяти, однако применение последней константы в качестве операнда представляется более надежным решением. 10.5. Рекурсивные процедуры Рекурсивной называется функция или подпрограмма, вызываю- щая самое себя. Для тех, кто не знаком с понятием рекурсии, та- кое определение может показаться странным; назначение подоб- ных подпрограмм представляется неясным, область их примене- ния — крайне ограниченной. В действительности рекурсивные процедуры вполне естествен- ны и широко применяемы. Задачи, решаемые традиционными итерационными или рекурсивными алгоритмами, выполняются большинством вычислительных машин быстрее при использова- нии итераций. Исключение составляют машины, широко исполь- зующие стеки, такие как ЭВМ В5000, В6000 и В7000 фирмы Burroughs. Однако скорость выполнения программы не всегда является определяющим фактором работы на ЭВМ. На практике часто важнее такие критерии, как простота программирования и легкость чтения программ. В самом деле, большинство приклад- ных программ пишутся на языках программирования высокого уровня, хотя при их написании на языке ассемблера можно до- биться большей эффективности использования ЭВМ. Рекурсии отдают предпочтение, когда с ее помощью алгоритм решения задачи выражается проще, чем в случае использования итерации. В учебной литературе простейшим примером рекур- сивной процедуры является вычисление факториала, описывае- мое в этом случае следующим образом: f(n) = n.f(n— 1) Хотя для вычисления факториала использование рекурсивной процедуры естественно, такой пример нельзя признать удачным, поскольку столь же просто вычисление факториала выполняется посредством итераций. Это демонстрирует приводимый ниже пример,
314 Глава 10 Д Пример 10.7. Итерационный алгоритм вычисления факториала на псевдокоде Ввести N Присвоить FACT значение 1 FOR COUNT := 2 ТО N DO Присвоить FACT значение FACT*COUNT END-FOR Вывести FACT Конец программы Большинство примеров использования рекурсии, реальных с практической точки зрения и естественных с позиции целесооб- разности ее применения, слишком сложны для того, чтобы быть здесь рассмотренными. Все же рассмотрим один пример приме- нения рекурсии, вполне естественный и весьма эффективный. Отметим только, что эту же задачу решает и итерационный ал- горитм. Д Пример 10.8. Рекурсивная функция • Постановка задачи Исходные данные (параметры) 1) адрес массива длинных слов, расположенных в порядке убывания их значений; 2) верхняя граница диапазона значений индекса элементов массива; 3) нижняя граница диапазона значений индекса элементов массива; 4) значение элемента, позиция которого в массиве подлежит определению. Искомый результат: позиция элемента с заданным значением в массиве, записанная в регистр R0 (в предположении, что от- счет позиций начинается с нуля). Способ решения задачи: использование рекурсивной процеду- ры бинарного поиска. Принцип бинарного поиска основывается на упорядоченности элементов массива. Сравнивая значение искомого элемента со значением элемента, занимающего позицию, соответствующую середине массива, можно определить, к какой половине массива принадлежит искомый элемент. Дальнейший поиск ограничи- вается половиной массива. Повторяя аналогичную процедуру для этой половины, сокращаем область поиска еще в два раза. В среднем число сравнений значения искомого элемента со зна- чениями элементов массива составляет log2n, где п — количество
Подпрограммы 315 элементов в данном массиве. При выполнении линейного поиска число подобных сравнений составляет в среднем п/2. (Линейный поиск предполагает последовательное сравнение значения иско- мого элемента со значением каждого элемента массива до тех пор, пока эти значения не совпадут.) Для массивов из сравни- тельно большого числа элементов бинарный поиск мс^кет быть выполнен намного быстрее, чем линейный поиск1). Например, для массива из 10 000 элементов бинарный поиск требует в сред- нем в 50 раз меньше сравнений, чем линейный поиск. После каждого сравнения алгоритм бинарного поиска при- меняется к половине оставшихся элементов массива, где пред- полагается местонахождение искомого элемента. Естественно та- кое повторное применение одного и того же алгоритма реали- зовать в виде рекурсивной процедуры. Приводимый ниже алго- ритм рекурсивного бинарного поиска (BINSER) представлен на псевдокоде в виде функции. Функции на языке ассемблера (по соглашению) возвращают результат своей работы в регистр R0. • Алгоритм решения задачи на псевдокоде Функция BINSER (LIST, LOWER-BOUND, UPPER-BOUND, TARGET) IF LOWER-BOUND > UPPER-BOUND THEN присвоить RO значение —1 (TARGET НЕТ В LIST) ELSE вычислить MID по формуле (UPPER-BOUND + LOWER_BOUND)/2 IF TARGET = LIST[MID] THEN присвоить RO значение MID ELSE IF TARGET < LIST[MID] THEN присвоить RO значение BINSER(LIST, LOWER-BOUND, MID -1, TARGET) ELSE присвоить RO значение BINSER(LIST, MID + 1, UPPER-BOUND, TARGET) ENDIF ENDIF ENDIF Возврат в вызывающий программный модуль Конец текста функции Первое предложение IF в этом алгоритме выявляет тот слу- чай, когда искомый элемент в массиве отсутствует. Необходи- мость подобной проверки для таких алгоритмов вполне очевид- на. Вызывающую программу информируют об ошибке путем за- писи — 1 в регистр R0. Описываемый бинарный поиск более известен под названием метода половинного деления или дихотомии, — Прим, ред.
316 Глава 10 Теперь можно перейти к записи алгоритма бинарного поиска на языке ассемблера. Приводимый ниже текст не включает вы- зывающую программу. Однако вслед за подпрограммой приве- дена последовательность команд, обеспечивающих вызов этой подпрограммы. • Программа на языке ассемблера .PSECT EXAMPLE, LONG ; ФУНКЦИЯ BIN SER ; РЕКУРСИВНЫЙ БИНАРНЫЙ ПОИСК ; ПАРАМЕТРЫ: ; LIST - АДРЕС УПОРЯДОЧЕННОГО МАССИВА ДЛИННЫХ ; СЛОВ ; LOWER-BOUND - НИЖНИЙ ПРЕДЕЛ ЗНАЧЕНИЙ ИНДЕКСА ; ЭЛЕМЕНТОВ МАССИВА, В КОТОРОМ ОСУЩЕСТВЛЯЕТСЯ ПОИСК ; UPPER-BOUND - ВЕРХНИЙ ПРЕДЕЛ ЗНАЧЕНИИ ИНДЕКСА ; ЭЛЕМЕНТОВ МАССИВА, В КОТОРОМ ОСУЩЕСТВЛЯЕТСЯ ПОИСК ; TARGET - ЗНАЧЕНИЕ ЭЛЕМЕНТА МАССИВА, ИНДЕКС ; (ПОРЯДКОВЫЙ НОМЕР) КОТОРОГО ПОДЛЕЖИТ ; ОПРЕДЕЛЕНИЮ; РАЗМЕР ЭТОГО ЧИСЛА РАВЕН ; ДЛИННОМУ СЛОВУ LIST = 4 LOWER-BOUND = 8 UPPER-BOUND = 12 TARGET = 16 MID = — 4 .ENTRY BINSER, ~M(R2) ; ВЫДЕЛЕНИЕ ДЛИННОГО СЛОВА ПАМЯТИ ДЛЯ УКАЗАТЕЛЯ MID ADDL2 #MID, SP ; ЕСЛИ LOWER-BOUND > UPPER-BOUND CMPL I OWER-BOUND(AP), UPPER.BOUND(AP) BLEQ LLSE1 ; TO ПРИСВОИТЬ RO ЗНАЧЕНИЕ -1 (В МАССИВЕ НЕТ ; ЭЛЕМЕНТА С ИСКОМЫМ ЗНАЧЕНИЕМ) MOVL # - 1, R0 BRW ENDIF 1
Подпрограммы 317 • ИНАЧЕ ВЫЧИСЛИТЬ MID = (UPPER-BOUND + L0WER_B0UND)/2 ELSE1: ADDL3 UPPER-BOUND(AP), LOWER-BOUND(AP), R2 DIVL3 #2, R2, MID(FP) • ЕСЛИ TARGET = LIST[MID] MOVL MID(FP), R2 CMPL TARGET(AP), @LIST(AP)[R2] BNEQ ELSE2 ; TO ПРИСВОИТЬ RO ЗНАЧЕНИЕ MID MOVL MID(FP), RO BRW END1F2 ; ИНАЧЕ. ЕСЛИ TARGET < LIST[MID] (ВСЕ ИНДИКАТОРЫ ЕЩЕ УСТАНОВЛЕНЫ) ELSE2: BGEQ ELSE3 ; TO ПРИСВОИТЬ RO ЗНАЧЕНИЕ BINSER(LIST, LOWER-BOUND ; MID — 1, TARGET) PUSHL TARGET(AP) SUBL3 # 1, MID(FP), - (SP) PUSHL LOWER-BOUND(AP) PUSHL LIST(AP) CALLS #4, BINSER BRW ENDIF3 ИНАЧЕ ПРИСВОИТЬ RO ЗНАЧЕНИЕ BINSER(LIST, MID + 1, UPPER-BOUND, TARGET) ELSE3: PUSHL TARGET(AP) PUSHL UPPER.BOUND(AP) ADDL3 #1, MID(FP), - (SP) PUSHL LIST(AP) CALLS #4, BINSER КОНЕЦ ОПЕРАЦИИ «ЕСЛИ» (ЕСЛИ TARGET < LIST[MID])
313 Глава 10 ENDIF3: ; КОНЕЦ ОПЕРАЦИЙ «ЕСЛИ» (ЕСЛИ TARGET = LIST[MID]) ENDIF2: ; КОНЕЦ ОПЕРАЦИЙ «ЕСЛИ» (ЕСЛИ LOWER-BOUND > ; UPPER-BOUND) ENDIF 1: RET Отметим, что для обеспечения доступа к фактическим пара- метрам используются именуемые константы, которым присваи- ваются значения, являющиеся смещениями относительно АР. Так, константа MID является смещением, отрицательным по от- ношению к FP, которое используется для доступа к длинному слову, динамически выделяемому при каждом вызове функции BINSER. Указанные константы делают легко читаемыми опе- ранды команд, имеющих дело с параметрами. Индекс элемента массива, подлежащего сравнению с иско- мым значением, формируется в динамически выделяемой обла- сти памяти с адресом MID(FP). Копия этого индекса записыва- ется в регистр R2, который используется для адресации к сравни- ваемому элементу массива. Строго говоря, в таком копировании необходимости нет. Однако индексирование является столь есте- ственным режимом работы с массивом, что его следует исполь- зовать везде, где это возможно. Поскольку LIST (АР)—это адрес, необходима команда PUSHL для загрузки адреса массива в стек. При использовании команды PUSHAL адрес массива был бы загружен в стек. Когда возникает необходимость загрузки в стек MID+1 или MID—1, применяются соответствующие команды сложения и вы- читания с автоуменьшением SP (указателя стека), используе- мого в качестве операнда — приемника таких команд. Можно было бы вычислить требуемое значение в регистре, а затем за- грузить в стек его содержимое, однако в данном случае отдано предпочтение решению поставленной задачи посредством одной команды, а не двух. Так часто решаются проблемы загрузки данных в стек и извлечения их оттуда. Несмотря на наличие в программном модуле трех вложен- ных предложений IF, его текст все еще сравнительно легко чи- таем. Это достигается смещением текста комментария (псевдо- кода) вправо в соответствии с глубиной вложения очередного предложения IF и использованием меток ENDIF*
Подпрограммы 319 Ниже приводится пример нерекурсивного внешнего вызова функции BINSER. А Пример 10.9. Обращение извне к функции BINSER • ОПРЕДЕЛЕНИЕ МЕСТОПОЛОЖЕНИЯ VALUE ; В STUDENT.NUMS PUSHL PUSHL PUSHL PUSHAL CALLS VALUE # (LENGTH- 1> #0 STUDENT_NUMS #4, BINSER ; ЕСЛИ RO: >=0 TSTL BLSS RO ELSE ; ТО ВЫВОД НА ПЕЧАТЬ R0 PRINT.L '''МЕСТОПОЛОЖЕНИЕ VALUE:', R0 BRW ENDIF ; ИНАЧЕ ВЫВОД НА ПЕЧАТЬ СООБЩЕНИЯ ОБ ОШИБКЕ ELSE: PRINT-L '''’“ОШИБКА: VALUE ОТСУТСТВУЕТ В' PRINT_L "'STUDENT-NUMS' КОНЕЦ ОПЕРАЦИИ «ЕСЛИ» ENDIF: Отметим, что рекурсивные обращения к BINSER (источни- ком которых является сама функция BINSER) используют команду PUSHL для передачи адреса массива, в то время как нерекурсивное обращение к BINSER (пример 10.9)— команду
320 Глава 10 PUSHAL. Это объясняется необходимостью при нерекурсивном обращении передавать действительный адрес массива, т. е. имя последнего, а при рекурсивных обращениях имя не нужно, до- статочно иметь только адрес массива. Реентерабельный (повторно используемый) программный мо- дуль не допускает какой-либо самомодификации в процессе вы- полнения. Не разрешается менять его команды; он не может со- держать области размещения данных, изменяемые в результате его работы. При таких условиях реентерабельным программным модулем могут пользоваться два или большее число пользовате- лей при работе в мультипрограммном режиме. Примером такого модуля может служить редактор текста, используемый для соз- дания программ на языке ассемблера. Независимо от числа про- граммистов, одновременно обращающихся к услугам одного и того же редактора текста, все они используют одну и ту же ко- пию этой системной программы. Это не только существенно эко- номит память, но и в тех случаях, когда у редактора есть обла- сти данных, содержимое которых подлежит модификации, си- стеме не нужно прослеживать, какому пользователю принадле- жит текущее содержимое этой области. Подпрограмма BINSER — пример реентерабельного про- граммного модуля. Вся его локальная память, за исключением R2 динамически выделяется из стека. Содержимое R2, сохраняе- мое в стеке посредством CALLS и возвращаемое вызывающему модулю командой RET, также носит характер значения динами- ческой переменной. 10.6. Библиотеки подпрограмм Теперь можно рассмотреть наилучший способ хранения и ис- пользования подпрограмм. Написанная и прошедшая стадию от- ладки подпрограмма может быть использована как часть си- стемы, для которой она написана, а также и для других систем. Наилучшая реализация этой возможности достигается при раз- дельной трансляции подпрограмм, прошедших отладку, с целью последующего их хранения в форме программных модулей на машинном языке (объектных модулей) в библиотеке подпро- грамм. В дальнейшем, будучи включенными в операции систем- ной программы LINK, эти подпрограммы могут быть присоеди- нены к рабочему модулю, подлежащему выполнению. Единственное изменение, в котором нуждается используемая таким образом подпрограмма, сводится к преобразованию в гло- бальные имена всех ее символических имен, доступных другим программным модулям. Все использованные в подпрограмме метки являются локальными, т. е. действительны только в пре- делах этого программного модуля на языке ассемблера. Чтобы
Подпрограммы 321 сделать их глобальными и тем самым доступными программе LINK, необходимо после имени каждой из них поставить еще одно двоеточие. Правило задания области действия метки фор- мулируется просто: одно двоеточие после имени означает, что метка — локальная, два двоеточия — глобальная. Аналогичным образом для указания того, что оператор присваивания опреде- ляет значение глобальной переменной (глобально доступного символического имени), следует использовать два следующих друг за другом знака операции присваивания («=»). Например, оператор FLAG= =5 делает символическое имя FLAG доступ- ным для всех объектных модулей в процессе установления свя- зей между ними. Отметим, что не рекомендуется делать доступными другим программным модулям символические имена, определяемые в данной подпрограмме. Для общения подпрограммы с «внешним миром» следует использовать список параметров. Для записи подпрограммы в библиотеку необходимо выпол- нить ее трансляцию, а после этого воспользоваться следующей командой DCL или VAX/VMS: $ LIBRARY/CREATE имя „библиотеки список „объектных „ программ В качестве имени библиотеки может быть использовано любое имя, формируемое по правилу наименования файлов. Список объектных программ — это перечень имен, прошедших трансля- цию программных модулей, которые необходимо поместить в библиотеку посредством указанной выше команды. Программ- ные модули, используемые для решения задач одного и того же проекта, обычно помещаются в одну и ту же библиотеку. Будучи созданной, библиотека может быть использована, если указать ее имя в команде LINK. Например, при желании разместить подпрограмму бинарного поиска в библиотеку, а затем ее при- менить при выполнении программы по имени SORTER, можно было бы воспользоваться следующими командами: $ MACRO BINSER $ LIBRARY/CREATE SERLIB BINSER $ MACRO SORTER $ LINK SORTER, SERLIB/LIB $ RUN SORTER 10.7. Подпрограммы и программа отладки Среди программных средств отладки VAX/VMS имеются два, относящиеся к подпрограммам: команда CALL и операция трас- сировки подпрограммы. Команда CALL имеет следующий обоб- 11 Зак. 483
322 Глава 10 щенный формат: CALL имя ^подпрограммы [(список_параметров)] Любая подпрограмма, подключаемая к выполняемому про- раммному модулю командой LINK, может быть выполнена по- средством программы отладки (так называемого отладчика) с помощью команды CALL. Для трассировки подпрограммы, ис- пользуемой при работе с отладчиком, точки трассировки могут быть установлены у всех команд вызова подпрограммы и воз- врата в вызывающий программный модуль посредством следую- щей команды: DBG > SET TRACE/CALL Выводы 1. В системе VAX стек выделяется системой. На его вершине находится доступный пользователю регистр SP, инициализируе- мый системой. 2. Команды PUSHR и POPR используются для записи со- держимого регистров в стек и извлечения из него соответствен- но. Операндами обеих команд является маска регистра, созда- ваемая посредством одноместной операции ~М. 3. Команды PUSHL и POPL предназначены для записи дан- ных размером длинное слово в стек и извлечения их оттуда со- ответственно. 4. Система VAX предоставляет быстрый (хотя и далекий от оптимального) способ создания и вызова подпрограмм посред- ством команд BSBB, BSBW, JSB и RSB. Этот способ требует, чтобы программист обеспечил поддержание целостности стека в процессе выполнения подпрограммы. При этом фактические параметры передаются только через регистры R0 и R1. 5. Для всех языков программирования, используемых систе- мой VAX, последняя предоставляет два способа создания про- цедур. 6. Команда CALLG применяется для передачи фактических параметров, например, блока памяти в вызывающий программ- ный модуль. Она также создает область памяти для стека, име- нуемую блок вызова, куда помещается на хранение информация о содержимом регистров и состоянии системы. 7. Использование команды CALLS является наиболее общим способом вызова процедур в системе VAX. Фактические пара- метры посылаются в стек, что обеспечивает функционирование как рекурсивных, так и реентерабельных процедур. 8. Доступ к фактическим параметрам в процедуре осуще- ствляется посредством косвенной адресации путем использова- ния содержимого регистра АР со смещением.
Подпрограммы 323 9. Подпрограммы можно транслировать самостоятельно, от- дельно от других программных модулей, помещать их в библио- теки, а затем посредством операции LINK включать в подлежа- щую исполнению программу. 10. Символические имена могут быть описаны как имена гло- бального доступа, если использовать два двоеточия вместо од- ного после каждого из них в команде или директиве, а также если использовать два следующих друг за другом знака при- сваивания вместо одного в операторах присваивания. 11. Возможна трассировка вызовов подпрограмм и возвраще- ния из них в вызывающий программный модуль. Подпрограммы можно выполнять самостоятельно посредством отладчика. Новые команды BSBB CALLS PUSHAB PUSHAW RET BSDW POPL PUSHAL PUSHL RSB CALLG POPR PUSHAQ PUSHR Новый символ операции ~M Новые термины Блок вызова Загрузка в стек Рекурсия Вызов по дескриптору Извлечение из стека Составное усло- вие Вызов по значению Маска регистров Стек Вызов по имени Глобальные символи- ческие имена Обработка особых ситуаций Процедура Субрутина Вопросы и упражнения 1. В направлении каких значений адресов растет стек в си- стеме VAX: больших или меньших? 2. Формирует ли команда PUSHL свой собственный код опе- рации? 3. Формирует ли команда POPL свой собственный код опе- рации? 4. Как загружать в стек целые числа размером слово? 5. Укажите все разновидности команды PUSHAx. 11*
324 Глава 10 6. Опишите операцию создания маски регистров. 7. В какой последовательности загружаются регистры в стек командой PUSHR? 8. В какой последовательности извлекаются регистры из сте- ка командой POPR? 9. Опишите все действия команды BSBW. 10. Напишите фрагмент программы на языке ассемблера, со-, ответствующий следующим операторам псевдокода a) WHILE (А > В) AND (С < = D) DO б) IF (А < = В) OR (С = D) THEN Приращение COUNT ENDIF в) IF (А()В) AND (C<=D) THEN вывод RESULT ELSE вывод сообщения об ошибке ENDIF 11. В каком порядке записывается в блок вызова содержи- мое регистров? 12. Какие биты PSW записываются на хранение в блок вы- зова? 13. Каковы критерии выбора одной из двух команд: CALLG и CALLS? 14. В чем отличие между подпрограммой, подлежащей вы- зову посредством команды CALLG, от той же подпрограммы, вызываемой командой CALLS? 15. Опишите процесс динамического выделения памяти в под- программе. 16. Зачем создаются реентерабельные подпрограммы? 17. Как можно сделать глобально доступным символическое имя, присвоенное целому числу размером длинное слово с по- мощью команды .LONG? Для задач (п. 18—25) составьте подпрограммы на языке ас- семблера и выполните их отладку. Для проверки их работоспо- собности напишите вызывающую программу для каждой под- программы. 18. Исходные данные (фактические параметры): а) адрес массива чисел, размер каждого из которых равен длинному слову; б) количество элементов массива в форме длинного слова. Требования к подпрограмме: использовать алгоритм сорти- ровки обменом для реорганизации массива чисел в порядке убы- вания их значений.
Подпрограммы 325 Примечание. Для проверки работоспособности подпрограм- мы следует использовать команду CALLG. 19. Исходные данные (фактические параметры): а) адрес упорядоченного массива целых чисел, размер каж- дого из которых равен слову, б) адрес размера (количества элементов) массива; в) целое число размером слово. Требования к подпрограмме', вставить данное целое число в массив, не нарушая его упорядоченности; откорректировать зна- чение размера массива. Примечание. Для проверки работоспособности подпрограммы следует использовать команду CALLG. 20. Исходные данные (фактические параметры): а) адрес строки текста на английском языке, содержащей менее 100 символов; все слова отделены друг от друга пробе- лами; нет знаков пунктуации (только строчные буквы и про- белы); б) адрес области памяти для строки символов, длина кото- рой равна 25; в) адрес области памяти для целого числа размером 1 байт. Требования к подпрограмме*, найти третье слово в данной строке текста на английском языке и поместить его в область памяти длиной 25. Исходный текст может и не содержать трех слов. Если третье слово найдено, то в область размером байт записать 1, иначе — 0. 21. Исходные данные (фактические параметры): а) адрес массива целых чисел, каждое из которых размером байт; б) адрес области памяти, содержащей значение размера мас- сива. Требования к подпрограмме*, исключить из массива все воз- можные повторяющиеся числа (элементы массива), не реоргани- зуя оставшиеся элементы; внести соответствующие изменения в области памяти, хранящей размер массива. 22. Исходные данные (фактические параметры): а) адрес массива целых чисел, каждое из которых размером байт; б) значение размера массива в виде длинного слова; в) адрес области памяти для хранения целого числа разме- ром слово. Требования к подпрограмме*, вычислить и записать в область памяти размером слово адрес элемента массива, значение кото- рого обеспечивает ему положение по середине упорядоченной последовательности элементов этого массива. Примечание. Для сортировки исходного массива следует со- ставить вторую подпрограмму, подобную подпрограмме в п. 18.
326 Глава 10 23. Исходные данные (фактические параметры): а) неотрицательное целое число размером длинное слово (ARG-1); б) неотрицательное целое число размером длинное слово (ARG-2). Требования к подпрограмме: вычислить значение функции Аккермана, определяемой следующим образом: А (О, ARG_2) =ARG_2 4-1 для всех ARG_2 > О A(ARG_1, 0) = A(ARG_I — 1,1) для ARG_I>0 A(ARG_1, ARG.2) —A(ARG_1 - 1, A(ARG_1, ARG_2— 1)) для ARG_1 и ARG_2>0 Примечание. Эта подпрограмма должна быть рекурсивной; следует обратить внимание, что она требует большой объем па- мяти для стека из-за больших значений параметров, а поэтому проверку ее работоспособности следует выполнять для сравни- тельно небольших значений (менее 10). 24. Исходные данные (фактические параметры): а) адрес строки символов (десятичных цифр в коде ASCII) ; б) значение длины строки символов. Требования к подпрограмме: записать значение числа, обра- зуемого цифрами в коде ASCII, в регистр R0. Примечание. Эта подпрограмма должна быть построена как рекурсивная процедура, выполняющая требуемые преобразова- ния. (Отметим, что числовое значение одного символа десятич- ной цифры в коде ASCII равно разнице между значением этого символа в коде ASCII и шестнадцатеричным числом 30, а число- вое значение строки из двух символов в коде ASCII равно сумме умноженного на 10 значения первого символа и значения вто- рого символа.) 25. Исходные данные (фактические параметры): а) положительное целое число N размером длинное слово-, б) положительное целое число М размером длинное слово. Требования к подпрограмме: определить количество различ- ных вариантов суммирования М положительных чисел с целью получения числа N. Это так называемая задача разбиения, ко- торую можно решить посредством следующих рекурсивных урав- нений: P(N, М) = 0 для N < М, Р(М, M) = P(N, 1)=1, N-1 P(N, М)= L P(I, М—1) для N>М 1=М—1
Глава 11 Макрокоманды В данной главе дается определение понятия макрокоманда, опи- сываются принципы построения и техника использования макро- команд языка ассемблера системы VAX. Макрокоманды позво- ляют расширять набор средств системы команд VAX, существен- но увеличивая тем самым возможности языка ассемблера. Ни- какое серьезное освоение программирования на языке ассембле- ра нельзя считать завершенным без понимания процесса созда- ния и применения макрокоманд. 11.1. Определение понятия «макрокоманда»1) В определенном смысле макрокоманду можно рассматривать как подпрограмму, выполняемую на этапе трансляции програм- мы, написанной на языке ассемблера. Так называемое макро- определение, подобно описанию подпрограммы на «языке» фор- мальных параметров, является указанием ЭВМ о необходимости выполнения некоторого вычислительного процесса. Однако мак- роопределение — это описание некоторого текста (команд или данных), подлежащего включению в программу, а также указа- ние на то, как использовать параметры для модификации этого текста при очередном обращении к макроопределению. Основное различие между обработкой вычислительной маши- ной программы, содержащей макрокоманды, и программы, со- держащей обращения к подпрограммам, заключается в следую- щем. Когда на этапе выполнения программы имеет место обра- щение к подпрограмме, ЭВМ выполняет ее и по завершении всех операций подпрограммы возвращает управление команде, непо- средственно следующей за командой вызова этой подпрограммы. Макрокоманды обрабатываются машиной уже на этапе трансля- ции программы подобно директивам языка ассемблера: проис- ходит обращение к макроопределению и соответствующий текст *> В оригинале для макрокоманды используется термин macro, а для языка ассемблера системы VAX-Macro; при этом операционная система VMS располагает системной командой MACRO для вызова транслятора языка ас- семблера. — Прим. ред.
328 Глава 11 (так называемое макрорасширение) помещается на место вызы- вавшей макрокоманды. На этапе выполнения такой программы указанный текст обрабатывается так же, как предшествующая и последующая части программы. Помимо этого, на этапе транс- ляции макрокоманды могут формировать директивы выделения памяти для данных. Иногда программисту приходится делать выбор между мак- рокомандами и подпрограммами. Поскольку макроопределение «вызывается» макрокомандой и включается в виде макрорасши- рения в текст программы уже на этапе трансляции, решение той или иной задачи посредством макрокоманд не требует (как при использовании подпрограмм) установления связей между про- граммными модулями на последующих этапах обработки про- граммы, а поэтому является более эффективным с точки зрения затрат времени на выполнение программы. Подпрограммы тре- буют наличия в памяти только одной копии своего текста и, сле- довательно, более эффективны с точки зрения рационального использования ресурсов памяти машины. Однако в большинстве случаев применения макрокоманд программист принимает реше- ние, руководствуясь не соображениями эффективности использо- вания машины, а стремясь к максимальному удобству програм- мирования. Основной целью включения макрокоманд в набор средств программирования является расширение номенклатуры системы команд языка ассемблера и предоставление транслятору допол- нительных директив. Макрокоманды позволяют не только созда- вать новые команды как комбинации команд базового набора (именуемого системой команд), но и давать новое определение функциональному назначению команд указанного набора в со- ответствии с требованиями той или иной конкретной программы. Все используемые в предыдущих главах и разделах команды ввода и вывода являются макрокомандами, формирующими об- ращения к соответствующим процедурам и обеспечивающими тем самым расширение возможностей базового набора команд. В то время как обращение к процедурам часто требует несколь- ко строк программы для записи передаваемых процедуре факти- ческих параметров, макрокоманда занимает только одну строку и, следовательно, более удобна для программиста, составляю- щего текст программы. 11.2. Макрокоманды без параметров В языке ассемблера системы VAX макрокомандами простейшей структуры являются макрокоманды без параметров. Хотя при- менение таких макрокоманд весьма ограниченно, знакомство с ними позволяет рассмотреть принципы построения и функциони-
Макрокоманды 329 рования макрокоманд, исключив проблему передачи параметров. Макроопределение, соответствующее макрокоманде без парамет- ров, имеет следующую обобщенную форму: .MACRO имя_макроопределения тело ^макроопределения .ENDM [имя_макроопределения} .MACRO — это директива для транслятора языка ассемблера, информирующая его о том, что далее следует макроопределение. Она присваивает имя макроопределению в соответствии с общим правилом формирования имен в языке ассемблера. Тело макро- определения— это, как правило, совокупность команд языка ас- семблера, определяющих последовательность реальных команд, включаемых в текст программы в результате обращения макро- команды к макроопределению. Указанные команды могут быть выполняемыми и (или) невыполняемыми. .ENDM — это директива, символизирующая конец макроопре- деления. За ней может быть указано (хотя это редко делается на практике) имя макроопределения. Начинающему программи- сту рекомендуется указывать это имя. Чтобы обратиться к макроопределению, его имя нужно запи- сать в строке программы так, как будто бы это — символическое обозначение кода операции некоторой команды. Транслятор раз- местит на месте этого имени тело макроопределения. Текст, соз- даваемый как часть программы в результате обращения к мак- роопределению, называется макрорасширением. Сказанное ил- люстрирует пример, приводимый ниже. Д Пример 11.1. Макроопределение без параметров .MACRO QUAD_R3 MULL2 R3, R3 MULL2 R3, R3 .ENDM QUAD_R3 Согласно данному макроопределению, содержимое регистра R3 возводится в четвертую степень и результат записывается в тот же регистр. При обращении к этому макроопределению посред- ством макрокоманды QUAD_R3 в текст программы включаются следующие команды: MULL2 R3, R3 MULL2 R3, R3 Нужно помнить, что на этапе выполнения программы ника- ких макроопределений нет. Они являются в определенном смыс-
330 Глава 11 ле входными данными этапа трансляции программы и участвуют в формировании текста на языке ассемблера, который либо ока- зывает влияние на процесс трансляции программы, либо преоб- разуется транслятором (ассемблируется) в машинный код, вы- полняемый ЭВМ на последующем этапе обработки программы — этапе ее выполнения. Макроопределения в той же мере аб- страктны, как и подпрограммы. Однако макрокоманды в дей- ствительности («физически») заменяются своими фактическими макроопределениями (макроопределениями, в которые помеще- ны фактические параметры) на этапе трансляции, в то время как обращения к подпрограммам заменяются своими фактиче- скими определениями (подпрограммами с фактическими пара- метрами) на этапе выполнения программы. После того как в тексте программы транслятор заменил макрокоманду ее факти- ческим макроопределением, макроопределение как некая аб- стракция перестает существовать, в то время как подпрограмма остается подобной абстракцией в листинге, выдаваемом трансля- тором по завершении своей работы. Когда транслятор «встречает» макроопределение, он просто его копирует в область памяти, специально предназначенную для макроопределения. Никаких других действий с последним транслятор не выполняет до тех пор, пока не встретится соот- ветствующая макрокоманда. Макрокоманды можно использовать для переопределения ко- дов операции (КОП) в наборе КОП системы VAX. Для каждой строки символов, обнаруженной транслятором языка ассемблера и воспринимаемой им (по контексту строки) как код операции, транслятор ищет соответствующее макроопределение, ранее об- наруженное в тексте программы или возможно указанное в биб- лиотеке макроопределений пользователя или вычислительной системы. Тогда, после того как такой поиск не увенчался успе- хом, транслятор обращается к таблице кодов операций набора команд. Следовательно, код операции воспринимается трансля- тором как символическое имя команды системы VAX только по- сле того, как выяснено, что это —не имя макрокоманды. При решении некоторых прикладных задач эта специфика работы транслятора может оказаться полезной. Однако в большинстве случаев, рассматриваемых в данной книге, такая возможность используется не для переопределения (задания новых функцио- нальных свойств) существующих кодов операций команд, а для расширения набора этих средств. После того как дано определение понятий макрокоманда и макроопределение, можно перейти к рассмотрению используе- мых ими параметров.
Макрокоманды 331 11.3. Передача параметров макроопределению Поскольку макрорасширение формируется на этапе трансляции, параметры, передаваемые макроопределению, не могут быть зна- чениями соответствующих переменных. Последние на этапе трансляции могут быть представлены только своими символиче- скими именами и значениями их адресов, задаваемыми в табли- це символических имен. Транслятор может манипулировать так- же и строками символов, которые, следовательно, могут быть ис- пользованы как параметры макрокоманд. При обращении к подпрограмме фактические параметры пе- редаются для замены формальных параметров обычно либо в виде значений переменных, либо в виде их адресов. Ни та ни другая форма представления параметров не пригодна для обра- щения к макроопределениям. Формируемые в результате подоб- ных обращений макрорасширения представляют собой тексты на языке программирования и поэтому только такая форма замены формальных параметров фактическими пригодна для макроопре- делений. 11.3.1. Простые параметры макрокоманд Основная форма представления формальных параметров в спи- ске параметров макроопределения имеет следующий вид: •MACRO имя список^параметров Параметры, указанные в списке, могут отделяться друг от друга запятыми, пробелами или функциями табуляции, однако обычно используются запятые. Эти же разделители можно применять для отделения имени макрокоманды от следующего за ним спи- ска параметров. Приводимый ниже пример иллюстрирует основ- ную форму представления как формальных, так и фактических параметров. Д Пример 11.2. Макрокоманда перестановки данных местами .MACRO SWAP.L VI, V2, V3 MOVL VI, V3 MOVL V2, VI MOVL V3, V2 .ENDM SWAP.L Макрокоманда SWAP LIST[R7], LIST[R8], TEMP
332 Глава И позволяет обращаться к приведенному выше макроопределению, в результате чего формируется следующее макрорасширение: MOVL LIST[R7], TEMP MOVL LIST[R8], LIST[R7] MOVL TEMP, LIST[R8] Данная макрокоманда используется для расширения возможно- стей набора команд языка ассемблера, обеспечивая обмен дан- ными между длинными словами памяти (подобной команды нет в базовом наборе команд языка ассемблера системы VAX). Включение такой макрокоманды (и соответствующего макро- определения) в текст программы целесообразно только в том случае, когда подобный обмен длинными словами требуется вы- полнять многократно. Если в макрокоманде указано больше параметров, чем это требуется вызываемому макроопределению, транслятор выдаст сообщение об ошибке. Если при обращении к макроопределению передается недостаточное количество фактических параметров, транслятор заполняет места недостающих параметров строками пробелов. Так, например, макрокоманда SWAP-L LIST[R7], LIST[R8] вызывает формирование следующей последовательно- сти команд (макрорасширения); MOVL LIST[R7], MOVL LIST[R8], LIST[R7] MOVL ,LIST[R8] Хотя отсутствие необходимых параметров в данных командах явится причиной последующих сообщений о синтаксических ошибках, иногда этим можно воспользоваться для стирания не- которых параметров, указанных в макроопределении. 11.3.2, Параметры, задаваемые по умолчанию Иногда отсутствие параметра в поле макрокоманды, для него предназначенного, указывает, что его значение принимается по умолчанию. Об этом может быть указано в списке формальных параметров макроопределения. Например, формальному пара- метру V3 макроопределения SWAR_L может быть присвоено имя TEMP следующим образом: .MACRO SWAP.L VI, V2, V3 = TEMP Теперь можно сформировать макрорасширение посредством той же неполной (по числу параметров в списке) макрокоманды SWAP_L разд. 11.3.1. В результате в текст программы вместо этой макрокоманды включается следующая последовательность
Макрокоманды 333 команд: MOVL LIST[R7], TEMP MOVL LIST[R8], LIST[R7] MOVL TEMP, LIST[R8] Эти команды являются копией макрорасширения, приведенного в начале разд. 11.3.1. Если символическое имя TEMP исполь- зуется в большинстве случаев обращения к данному макроопре- делению, то такая форма задания этого параметра (задание по умолчанию в макрокоманде) делает более простой запись текста программы, поскольку вместо многократного повторения имени TEMP в макрокомандах оно записывается только один раз в макроопределении. Подобное задание фактических параметров столь же эффективно, когда по умолчанию используется не один, а несколько параметров. Если подобный параметр находится не в конце списка, то, несмотря на его отсутствие, соответствующие разделители (запятые) должны быть включены в список, иначе транслятор может неправильно идентифицировать формальный параметр очередному фактическому. 11.3.3. Ключевые параметры Ошибок установления транслятором несоответствия между фор- мальными и фактическими параметрами можно избежать, если использовать так называемые ключевые параметры, отказав- шись от идентификации параметров по их позиции в списке 1). Ключевой параметр задается в списке параметров макрокоман- ды согласно следующей обобщенной форме записи: имя-формалъного-параметра = имя-фактического-параметра Например: SWAP-L V2=LIST[R8], V1 = LIST[R7], V3=TEMP. В результате обращения к соответствующему макроопределению эта макрокоманда создает точно такое же макрорасширение, как одноименная макрокоманда предыдущего раздела. Использование имен формальных параметров в макрокоман- де делает необязательным соблюдение порядка чередования па- раметров в списке. Применение ключевых параметров позволяет избежать ошибок при работе с макрокомандами, содержащими большое количество параметров. (На практике трудно запомнить порядок расположения более шести параметров макрокоманды.) Ключевые параметры широко используются в макрокомандах ввода-вывода, являющихся составной частью системного про- граммного обеспечения VMS (см. гл. 14). До сих пор рассматривались только такие параметры, обычно именуе- мые позиционными. — Прим. ред.
334 Глава 11 J 1.3.4. Параметры в виде строк символов Если параметр макрокоманды — не символическое имя или кон- станта, а строка символов, то часто возникает необходимость в применении ограничителей таких фактических параметров. В ка- честве ограничителей обычно используют угловые скобки «<» и «>». Но если строка символов содержит эти знаки, необхо- димо другое решение. Например, в качестве ограничителя стро- ки можно использовать какой-либо другой символ, располагая его перед началом и после окончания строки символов и указа- ния перед такой записью строки знак « ~». Именно так заданы литералы во всех макрокомандах PRINT-х, встречающихся в программах предыдущих глав. Параметры в виде строк симво- лов, не содержащих знаки — разделители параметров (запятые, пробелы или функции табуляции), не нуждаются в использова- нии ограничителей. Строки символов широко применяются в качестве парамет- ров в макрокомандах PRINT-х. Эти макрокоманды (именуемые командами вывода) формируют символьные константы в соот- ветствии с кодом ASCII для первых параметров, указывыемых в их списке. Об этом свидетельствует приводимый ниже пример. Д Пример 11.3. Параметры в виде строк символов .MACRO PRINT.L LABEL, ... LAB: .ASCII @LABEL@ .ENDM Теперь читателю должны стать более понятными подобные мак- рокоманды и их макроопределения. 11.3.5 . Сцепление параметров Параметры макрокоманды можно сцеплять либо с константа- ми — строками символов (так называемыми символьными кон- стантами), либо с другими параметрами. Символом операции сцепления параметров макрокоманды является апостроф («'»). Для сцепления параметра с константой в виде строки символов используется один апостроф, для сцепления двух параметров — два апострофа, Следует различать два апострофа от кавычек
Макрокоманды 335 (”). Хотя кавычки и похожи на следующие друг за другом апо- строфы, они (кавычки) являются одиночным знаком. Операцию сцепления параметров можно применить к макро- команде SWAP-L для придания ей большей гибкости при ис- пользовании. Вместо того чтобы ее применение ограничивать длинными словами, можно расширить сферу ее применения на операнды размером байт, слово и двойное длинное слово, пере- давая размер операнда в качестве дополнительного параметра. Параметр размер, который может быть представлен единствен- ным символом, сцепляется с базовым именем кода операции — именем MOV — для формирования требуемого варианта коман- ды. Пример нового определения рассматриваемой макрокоманды, называемой теперь SWAP, приводится ниже. Д Пример 11.4. Параметры, задаваемые по умолчанию .MACRO SWAP VI, V2, V3 = TEMP, SIZE = L MOV'SIZE VI, V3 MOV'SIZE V2, VI MOV'SIZE V3, V2 .ENDM Макрокоманда SWAP, обращающаяся к данному макроопре- делению, и создаваемое в результате макрорасширение имеют следующий вид: SWAP LIST[R7[, LIST[R8], , Q MOVQ LIST[R7], TEMP MOVQ LIST[R8], LIST[R7] MOVQ TEMP, LIST[R8] 11.3.6 . Формирование уникальных символических имен Если макрокоманда формирует в макрорасширении какую-либо метку, то такая же метка создается при каждом обращении макрокоманды к тому же самому макроопределению. Поскольку при многократном обращении к такому макроопределению в од- ной и той же программе формируется несколько одинаковых меток (транслятор создает несколько определений одной и той же метки), возникает конфликтная ситуация. Хотя решение подобной проблемы возможно путем передачи метки макроопределению в качестве фактического параметра, существует лучшее решение, обычно используемое многими язы- ками программирования. Поскольку в процессе трансляции про- граммы очень просто вести подсчет количества создаваемых макрорасширений, можно использовать показания такого счет- чика в качестве числа, добавляемого к числу 29999, для форми- рования очередной метки. Формируемые таким образом метки
336 Глава И принято называть локальными. Они представляют собой число- вые константы целого типа, за которыми указывается знак дол- лара («$»). Поскольку формируемые указанным способом кон- станты имеют значения 30000, 30001 и т. д. (2999+ I, 29999 + 2 и т. д.), то соответствующие метки имеют вид: 30000$, 30001$ и т. д. Более подробно локальные метки рассматриваются в гл. 15. Чтобы заставить транслятор формировать уникальную (от- личную от других) локальную метку при каждом обращении к макроопределению, необходимо поместить требуемые метки в конце списка формальных параметров и указать перед каждой меткой знак вопроса («?»). После этого такими метками можно пользоваться, не заботясь о возможности появления их дублика- тов при многократных обращениях к одному и тому же макро- определению, поскольку транслятор заменит эти метки соответ- ствующими локальными метками. Фактические параметры, ука- зываемые в макрокоманде, не могут соответствовать формаль- ным параметрам, задаваемым в виде описанных меток. Форми- руемые таким образом метки являются в определенном смысле исключительными параметрами и не должны каким-либо обра- зом зависеть от общепринятого определения фактических пара- метров. Приводимый ниже пример иллюстрирует технику формирова- ния строк символов в соответствии с кодом ASCII посредством макрокоманд; здесь же показано, как можно «обойти» такие строки посредством команд передачи управления. Д Пример 11.5. Формирование уникальных символических имен .MACRO STRING-BUILDER STRING, STRING-LABEL ?ARND BRB ARND STRING-LABEL: .ASCII /STRING/ ARND: .ENDM Ниже приводятся макрокоманды, обращающиеся к указан- ному выше макроопределению STRING-BUILDER и формирую- щие соответствующие макрорасширения. STRING-BUILDER ЭТО КОГДА-НИБУДЬ КОНЧИТСЯ?', QUESTION BRB . 30000$ QUESTION: .ASCII /ЭТО КОГДА-НИБУДЬ КОНЧИТСЯ?/ 30000$: STRING-BUILDER ~'СКОРО, СКОРО', ANSWER BRB 30001$ ANSWER: .ASCII /СКОРО, СКОРО/ 80001$
Макрокоманды 337 Типичным применением макрокоманд является вызов про- цедур. Хотя программирование с использованием процедур яв- ляется наиболее эффективным (с точки зрения экономии памя- ти) способом абстрактного представления программы, реализа- ция вызова процедур весьма не проста, особенно если для пере- дачи параметров применяется стек. Предположим, что имеется процедура вывода на печать стро- ки из десяти символов кода ASCII, имеющей фиксированную длину, и данных размером длинное слово. (Речь идет о крайне ограниченной по своим возможностям модификации макро- команды PRINT-L.) Параметрами этой процедуры, именуемой PRINT, являются адрес строки символов и значение данных раз- мером длинное слово. Ниже приводится пример макроопределе- ния для макрокоманды, осуществляющей вызов рассматривае- мой процедуры. Д Пример 11.6. Вывод на печать заголовка в виде строки из 10 символов и содержимого длинного слова памяти •MACRO PRINT.L STRING, VALUE, ?ARND, LAREL: BRB .ASCII ?LABEL ARND @STRING@ ARND: PUSHL PUSHAB CALLS .ENDM VALUE LABEL #2, PRINT 11.4. Операции над строками символов Язык ассемблера системы VAX располагает тремя встроенными функциями для обработки строк символов, представленных в коде ASCII. Эти функции можно использовать только внутри макроопределений и в пределах повторно выполняемых блоков, рассматриваемых в разд. 11.5. Функция % LENGTH позволяет определить длину указанного параметра и имеет следующую обобщенную форму: %LENGTH (строка) где строка — это параметр макрокоманды или строка символов, представляющая собой константу и выделяемая угловыми скоб- ками или специально определяемым символом-ограничителем.
338 Глава 11 Рассмотрим в качестве примера следующие строки программы: %LENGTH (STRING) LEN_FRUIT = %LENGTH ((ЯБЛОКИ И ВИНОГРАД)) %LENGTH Г* ОШИБКА: ПЕРЕПОЛНЕНИЕ ТАБЛИЦЫ*) В первой строке определяется длина параметра, именуемого STRING. В следующих двух строках выполняется аналогичный подсчет количества символов параметров в процессе набора тек- ста последних на клавиатуре терминала. (Во второй строке вы- числяемая длина параметра присваивается переменной с симво- лическим именем LEN-FRUIT.) Основное назначение функции % LENGTH — определение длины параметров макрокоманды. Функция % LOCATE выполняет в процессе трансляции ту же роль, что и команда МАТСНС на этапе выполнения программы. Эта функция имеет следующую обобщенную форму: % LOCATE (строка_1, строка_2 [, позиция]) Первый параметр (строка-1) определяет цель поиска: это— па- раметр макрокоманды или выделенная ограничителем строка символов, играющая роль константы. Второй параметр (ст ро- ка __ 2) является строкой — источником исходных данных поиска и представляет собой параметр макрокоманды или выделенную ограничителями строку символов, играющую роль константы. Третий параметр, необязательный к употреблению, указывает, с какой позиции должен начинаться поиск в строке_2. Позиция указывается целым числом с учетом того, что номер позиции первого символа строки равен нулю. В поле задания третьего параметра должно быть указано или символическое имя с абсо- лютным адресом, или десятичная константа. Результат вычислений, выполняемых посредством функции % LOCATE «JOEV'JOE JOEFFRIES', 2) равен 4 потому, что таков номер позиции первой буквы слова JOE, второй раз встречающегося в исходной строке; поскольку в качестве начала поиска указана позиция 2 (позиция буквы Е), то первая запись этого слова не попадает целиком в «поле зре- ния» данной функции. Если найти искомую строку (строку-1) не удается, то функция % LOCATE в качестве результата выдает длину исходной строки (строки_2). Именно это происходит в результате обращения к «услугам» функции % LOCATE r'MARY', (MARTINI)) Формируемый ею числовой результат равен 7. Поскольку третий параметр функции отсутствует, поиск начинается с первой (рав- ной нулю) позиции исходной строки,
Макрокоманды 339 Функция % EXTRACT извлекает подстроку из заданной стро- ки. Эта функция имеет следующую обобщенную форму: % EXTRACT (символическое _имя_1, символическое _имя_2, строка) В качестве первого параметра (символическое_имя_1) должно быть использовано символическое имя, имеющее абсолютный адрес в памяти ЭВМ, или десятичная константа. Этот параметр указывает начальную позицию подстроки, подлежащей извле- чению. Второй параметр (символическое-имя-2) задается, так же как и первый параметр, и служит для указания длины извле- каемой подстроки. В качестве третьего параметра (строки) должна быть задана исходная строка, из которой извлекается указанная подстрока. Такой строкой является либо параметр макрокоманды, либо выделенная ограничителями строка сим- волов кода ASCII, играющая роль константы. Результатом ис- пользования, например, функции % EXTRACT (0,4, (ALKA-SELTZER)) является подстрока ALKA. 11.5. Циклы на этапе трансляции и трансляция по условию Хотя описываемые в данном разделе средства языка ассемблера могут показаться несколько специфическими, они являются весь- ма мощным инструментом программирующего на языке ассемб- лера. 11.5.1. Циклы Циклы, выполняемые на этапе трансляции программы на языке ассемблера системы VAX, содержат команды, которые должны быть включены в текст программы более одного раза. В то вре- мя как эти циклы часто появляются внутри макроопределений, они могут появляться также и в любом другом месте программы на языке ассемблера. Чтобы построить цикл, который желательно иметь повторен- ным в программе требуемое количество раз, следует воспользо- ваться директивой .REPEAT, имеющей следующую обобщенную форму: .REPEAT выражение В качестве операнда выражение необходимо использовать абсо- лютное выражение. Команды, текст которых подлежит повторе- нию, завершаются директивой .ENDR. Количество раз, которое
340 Глава 11 команды, заключенные между директивами .REPEAT и .ENDR, должны появиться в тексте программы, задается значением вы- ражения директивы .REPEAT. Если это значение меньше или равно нулю, то указанные команды вообще не включаются в текст программы. Следовательно, конструкция .REPEAT—.ENDR является циклом с предварительной проверкой условия его окон- чания. Приводимый ниже пример иллюстрирует использование этих директив для пропуска (заполнения пробелами) десяти строк в выводимом на печать документе — результате работы программы. Д Пример 11.7. Простой цикл на этапе трансляции .REPEAT 10 PRINT_L .ENDR Этот цикл формирует в тексте программы 10 команд PRINT-L. 11.5.2. Символические имена как параметры и их значения Ранее отмечалось, что содержимое областей памяти и регистров нельзя использовать в качестве фактических параметров макро- команд, поскольку на этапе трансляции программы это содер- жимое еще не определено. Единственными числовыми значения- ми, которые уже могут быть известны на этапе трансляции, а следовательно, и использованы в качестве фактических парамет- ров при обращении макрокоманд к соответствующим макроопре- делениям, являются адреса символических имен. Причем реаль- но в программе можно воспользоваться только теми символиче- скими именами, которым поставлены в соответствие определен- ные адреса памяти посредством операторов присваивания. Та- кие символические имена обычно применяются для обозначения адресных констант; из таких имен и соответствующих им значе- ний транслятор формирует таблицу символических имен. Иногда возникает необходимость обратиться к макроопреде- лению, передав ему непосредственно значение адреса символи- ческого имени, а не имя в виде строки символов кода ASCII. Такая задача возникает при формировании посредством макро- команд последовательности команд языка ассемблера, опери- рующих с содержимым регистра, номер которого не известен до момента обращения макрокоманды к макроопределению. Воз- можным решением подобной задачи является присвоение номера регистра некоторому символическому имени в качестве значения адреса. Это значение может быть указано в качестве фактиче- ского параметра макрокоманды. Для этого достаточно поместить перед ним знак «\». В результате замены формального пара-
Макрокоманды 341 метра макроопределения на такой фактический параметр ука- занное значение адреса превращается в строку десятичных цифр, представленных в коде ASCII. Эта строка окажется расположен- ной во всех позициях соответствующего формального параметра макроопределения. В качестве примера подобного решения рас- смотрим задачу формирования последовательности команд, очи- щающих несколько регистров, следующих друг за другом по но- мерам, начиная с регистра R0. Исходным условием решения за- дачи является число подлежащих очистке регистров. Если соз- дать макроопределение, формирующее команду CLRL, в которой номер очищаемого регистра задан в виде имени переменной, то можно поместить такое макроопределение в тело цикла, выпол- няемого на этапе трансляции и использующего счетчик количе- ства очищенных регистров. Приводимый ниже пример иллю- стрирует возможный вариант такого решения. А Пример 11.8. Сцепление параметров со строкой символов, играющей роль константы .MACRO CLREG REG-NUM CLRL R'REG_NUM .ENDM Это макроопределение используется следующим фрагментом программы: REG_NUM = 0 .REPEAT 5 CLREG /REG_NUM REG-NUM = REG-NUM + 1 .ENDR В результате обращения к макроопределению формируется по- следовательность команд CLRL R0 CLRL Rl CLRL R2 CLRL R3 CLRL R4 11.5.3. Циклы co списком значений параметра Весьма часто требуются циклы, выполняемые на этапе трансля- ции и использующие при каждом повторении очередной элемент из списка значений параметра цикла. Для этих целей служит
342 Глава 11 директива .IRP, имеющая следующую обобщенную форму: .IRP имя, {список} Эта директива похожа на макрокоманду с единственным пара- метром (символическим именем). Первоначально этот параметр принимает значение, равное первому элементу списка, и форми- руется последовательность команд, определяемая текстом макро- определения, расположенного между директивами .IRP и .ENDR. Затем этот процесс повторяется для второго элемента списка (в предположении, что последний содержит по меньшей мере два элемента). Подобные действия продолжаются до тех пор, пока список элементов не окажется исчерпанным (или ЭВМ выйдет из строя!). Символическое имя директивы JRP исполь- зуется так же, как и символические имена параметров макро- определения. Такое имя не имеет собственного значения, а за- меняется поочередно элементами списка значений параметра описываемого цикла до тех пор, пока список не будет исчерпан. Приводимый ниже пример макроопределения содержит процеду- ру вывода на печать строки символов, выполняющей роль лите- рала и содержимого четырех длинных слов памяти. Это некото- рый, ограниченный по своим возможностям вариант команды PRINT-L. Параметры процедуры, именуемой PRINT, — это дли- на строки-литерала (измеряемая количеством длинных слов), адрес строки и значений четырех длинных слов. А Пример 11.9. Вывод на печать заголовка и значений четырех длинных слов .MACRO .IRP PUSHL .ENDR PUSHAB PUSHL CALLS BRB STR: .ASCII ARND: .ENDM PRINT-L STRING, VAL1, VAL2, VAL3, VAL4, ?STR, ?ARND ARG, (VAL4, VAL3, VAL2, VAL1) ARG STR # < % LENGTH (STRING)) #6, PRINT ARND ©STRING® В этом макроопределении с помощью директивы .IRP формиру- ются четыре команды PUSHL для загрузки значений четырех длинных слов в стек. Для того чтобы строка-литерал могла быть переменной длины, используется функция % LENGTH, которая определяет значение этой длины, пересылаемой затем процедуре. Реже, чем описанные выше, используются на практике цик- лы, выполняемые на этапе трансляции использующие при каж-
Макрокоманды 3'3 дом повторении очередной символ из строки символов, играю- щей роль списка значений параметра цикла. Для этих целей при- меняется директива .IRPC, имеющая следующую обобщенную форму: .IRPC имя, {строка} Строка символов должна быть выделена ограничителями — уг- ловыми скобками ((и)) или специально определяемыми ограни- чителями (символами) с указанием об этом посредством зна- ка «~». Директивы JRP и .IRPC позволяют выполнять или не выпол- нять трансляцию некоторых фрагментов программы в зависимо- сти .от выполнения или невыполнения определенных условий. Трансляция по условию обеспечивает обработку блоков текста программы на языке ассемблера VAX, если заданное условие выполняется (оказывается «истинным»). 11.5.4. Трансляция по условию Иногда программа содержит две или более взаимоисключающие секции: при конкретном выполнении программы используется только одна из них. Машинные коды неиспользуемой части про- граммы совершенно неоправданно занимают место в памяти. Хотя для вычислительной системы с виртуальной памятью, по- добной системе VAX, такой расход памяти не создает серьезных проблем, однако рациональнее в листинге программы, прошед- шей трансляцию, и в ее объектном модуле иметь только те сек- ции, которые используются на этапе выполнения. Языком ас- семблера системы VAX предусмотрена такая структура про- грамм на этапе трансляции, которая допускает выбор частей программы, подлежащих преобразованию в машинные коды. Для этих целей используется так называемая директива выбора, имеющая следующую обобщенную форму: •IF условие операнд(ы) Блок команд, подлежащих трансляции при выполнении опреде- ленного условия, завершается другой директивой — .ENDC. У директивы .IF один или два параметра операнда в зависи- мости от условия, подлежащего проверке. Если в качестве един- ственного операнда используется абсолютное выражение, то в качестве возможных условий используются следующие: EQUAL (или EQ —РАВНО), NOT-EQUAL (или NE — НЕ РАВНО), GREATER (или GT —БОЛЬШЕ), LESS-THAN (или LT— МЕНЬШЕ), GREATER-EQUAL (или GE — БОЛЬШЕ ИЛИ РАВНО), LESS-EQUAL (или LE —МЕНЬШЕ ИЛИ РАВНО). Если единственным операндом является символическое имя, то возможны условия DEFINED (или DF — ОПРЕДЕЛЕНО), либо
344 Глава 11 NON-DEFINED (или NDF —НЕ ОПРЕДЕЛЕНО). Если дирек- тива содержит два операнда, они воспринимаются как парамет- ры макросредств, а возможными условиями для них являются IDENTICAL (или IDN — ИДЕНТИЧНЫЕ), либо DEFFERENT (или DIF — РАЗЛИЧНЫЕ). Если директива содержит только один такой операнд (параметр макроопределения), то возмож- ными к употреблению условиями являются BLANK (или В — ПРОБЕЛ), либо NON-BLANK (или NB — НЕ ПРОБЕЛ). В ка- честве примера выбора подлежащего трансляции текста про- граммы ниже приведена модификация макроопределения SWAP, рассмотренного в примере 11.2. Д Пример 11.10. Трансляция по условию .MACRO SWAP VI, V2, V3 .IF BLANK V3 MOVL VI, -(SP) MOVL V2, VI MOVL (SP) + , V2 .ENDC .IF NON_BLANK V3 MOVL VI, V3 MOVL V2, VI MOVL V3, V2 .ENDC .ENDM Если третий параметр в макрокоманде отсутствует, первый блок транслируется, а второй игнорируется. Если же третий параметр имеется, то игнорируется первый блок, а транслируется второй. Трансляция по условию может применяться и тогда, когда желателен селективный подход к трансляции блоков, располо- женных в нескольких местах программы на языке ассемблера. Независимо от количества таких блоков принятие решения о трансляции сразу всех блоков можно выполнить посредством одного оператора присваивания, определяющего значение флаж- ка разрешения трансляции. В языке ассемблера системы VAX имеются также директивы, обеспечивающие принятие решения о трансляции отдельных ча- стей программы посредством конструкции, аналогичной предло- жению ELSE псевдокода. Начало подобной конструкции поме- чается директивой .IF-FALSE, предполагающей, что предложе- ние THEN выбирается при положительном результате проверки условия. Если требуется противоположное решение, в качестве заголовка конструкции ELSE используется директива .IF-TRUE.
Макрокоманды 345 Если же необходимо при любом условии выполнить трансляцию, то применяется директива .IF-TRUE-FALSE. Приводимый ниже пример является записью макроопределения примера 11,10 с по- мощью конструкции ELSE, заменившей два отдельно используе- мых условия. Д Пример 11.11. Трансляция по условию посредством предложения .MACRO SWAP VI, V2, V3 .IF BLANK V3 MOVL VI, -(SP) MOVL V2, VI MOVL (SP) + , V2 .IF_FALSE MOVL VI, V3 MOVL V2, VI MOVL V3, V2 .ENDC .ENDM Трансляцию по условию единственной команды можно выпол- нить и с помощью директивы .IF, однако для этого требуется три строки текста программы. Эту задачу решает проще дирек- тива .IIF (непосредственное IF), имеющая следующую обобщен- ную форму: .IIF условие операнд(ы), команда В качестве условия и операндов этой директивы используется то же, что и для директивы .IF. В поле команда может быть указана любая команда языка ассемблера. Эта директива явля- ется разновидностью директивы .IF, записываемой в виде одной строки. Поскольку может быть выполнена по условию трансля- ция только одной команды, директива .ENDC не требуется. При- водимая ниже директива Л IF только в том случае формирует команду очистки области памяти COUNT размером длинное сло- во, когда в таблице символических имен имени FLAG соответ- ствует нулевое значение. .IIF EQUAL FLAG, CLRL COUNT 11.6. Прочие директивы Для выхода из макрорасширения при выполнении некоторого условия используется директива .MEXIT. Пример использования такой директивы • IIF EQUAL FLAG, .MEXIT
316 Глава 11 .MEXIT можно использовать также для выхода из циклов, вы- полняемых на этапе трансляции. Если эта директива принадле- жит вложенному (внутреннему) макрорасширению или циклу этапа трансляции, то ее функция — передача управления соот- ветствующему охватывающему (внешнему) макрорасширению или циклу. Директива .NARG дает возможность формировать очень гиб- кие по структуре макрорасширения. Обобщенная форма этой ди- рективы имеет следующий вид: .NARG символическое „имя Функции этой директивы просты: осуществляется подсчет коли- чества фактических параметров, передаваемых макроопределе- нию при обращении к нему, и присвоение результата символи- ческому имени в качестве значения некоторого адреса. Дирек- тиву .NARG можно употреблять только в макроопределениях. Директива .NCHR имеет следующую обобщенную форму: .NCHR имя, {строка„символов) Она используется для присвоения числа символов в заданной строке указанному имени таблицы символических имен в каче- стве значения некоторого адреса. Строка должна быть заключе- на в угловые скобки, если она не содержит запятых, пробелов, функций табуляции или точек с запятой; в противном случае для выделения строки нужно использовать специально опреде- ляемые ограничители с указанием перед первым из них знака «~». Отметим, что если директиву .NARG можно применять только в макроопределениях, то директиву .NCHR разрешается использовать в любой части программы на языке ассемблера. Макроопределение, формирующее вызов процедуры, которая ранее применялась для вывода на печать содержимого длинных слов памяти, использует программные средства трансляции по условию и директиву .NARG для подсчета количества парамет- ров. Для обращения к процедуре требуются следующие пара- метры: число подлежащих выводу на печать длинных слов, дли- на строки-литерала, адрес этой строки и значения выводимых на печать длинных слов. Ниже приводится текст описываемого мак- роопределения. Д Пример 11.12. Макроопределение PRINT.L .MACRO PRINT.L STRING, VI, V2, V3, V4, V5, V6, ?LAB, ?ARND .NARG COUNT .IRP ARG, <V6, V5, V4, V3, V2, VI) .IIF NOT.BLANK, ARG, PUSHL ARG .ENDR
Макрокоманды 347 PUSHAB LAB PUSHL #(%LENGTH(STRING)) PUSHL # (COUNT-1) CALLS #(COUNT+ 2) PRINT BRB ARND LAB: .ASCII ©STRING® ARND: .ENDM Отметим, что результат выполнения директивы .NARG исполь- зуют как параметр процедуры, указывающий число выводимых на печать данных, так и первый операнд команды CALLS. Ди- ректива .IIF служит для загрузки в стек значений всех пересы- лаемых длинных слов. 11.7. Управление включением макрорасширения в листинг трансляции По умолчанию команды, составляющие текст макрорасширения, не включаются в текст программы (листинг), который трансля- тор выводит на печать. Принудительно (путем явного указания) в листинг могут быть включены либо только выполняемые ко- манды макрорасширения, либо все команды. В обоих случаях, но с различными параметрами EXPANSIONS (или ME — для макрорасширений) и BINARY (или ВЕМ —для так называемых бинарных макрорасширений) для этого используют директиву .SHOW, имеющую следующую обобщенную форму: .SHOW параметр Параметр EXPANSIONS указывает на необходимость включе- ния в листинг всего текста макрорасширения, параметр BINA- RY — на включение только выполняемых команд. Действие директивы .SHOW можно отменить посредством директивы .NOSHOW. Например, если указана директива .SHOW EXPANSIONS но требуется отказаться от ее «услуг», то достаточно воспользо- ваться директивой .NOSHOW EXPANSIONS В директивах .SHOW и .NOSHOW можно задавать несколько дополнительных параметров (см. Руководство по программиро- ванию на языке ассемблера VAX-11). Отметим, что действия, аналогичные вызываемым данными директивами, выполняются при использовании директив .LIST и .NLIST,
348 Глава 11 Выводы 1. Макросрёдства— это средства программирования, реали- зуемые на этай'е трансляции и позволяющие расширить набор команд вычислительной машины. 2. Директивы .MACRO и .ENDM используются для указания соответственно начала и конца макроопределения. Имя макро- определения и его формальные параметры указываются как опе- ранды директивы .MACRO. 3. Отсутствующему фактическому параметру по умолчанию в макрорасширении ставится в соответствие пустая строка сим- волов (строка пробелов). Значения, задаваемые формальным параметром по умолчанию, могут быть присвоены последним с помощью директивы .MACRO. При использовании ключевых па- раметров их значения присваиваются формальным параметрам макроопределения при обращении к последнему. 4. Строки символов могут быть переданы макроопределению как фактические параметры, однако для этого часто требуется их выделять символами-ограничителями. Формальные парамет- ры можно сцеплять с другими параметрами, используя для за- дания операции сцепления два апострофа, или со строками, иг- рающими роль констант, используя для тех же целей единствен- ный апостроф. 5. Значение символического имени как значение адреса мо- жет быть передано в качестве фактического параметра, если перед этим символическим именем указать знак «\». 6. Уникальные (не похожие друг на друга) метки могут быть сформированы в макроопределении, если в списке формальных параметров перед соответствующими именами меток поместить вопросительные знаки. При каждом обращении к макроопреде- лению такая метка получает новое (уникальное) имя. 7. Функции % LENGTH, % LOCATE и % EXTRACT являются функциями, определяющими операции над строками символов, выполняемыми на этапе трансляции. Эти функции применимы только в макроопределениях и повторяющихся блоках. Функция % LENGTH определяет измеряемую количеством символов длину строки, используемой как параметр макроопределения. Функция % LOCATE вызывает выполнение на этапе трансляции тех же операций, что и функция МАТСНС на этапе выполнения про- граммы. Функция % EXTRACT удаляет подстроку из данной строки. 8. Директива .REPEAT используется для создания цикла, по- вторяемого на этапе трансляции заданное число раз. Директива .IRP формирует подобный цикл, число повторений которого опре- деляется длиной списка значений параметра цикла. Директива JRPC по функциям подобна директиве .IRP, но вместо списка
Макрокоманды 349 значений параметра цикла использует строку символов, длина которой определяет число повторений цикла. 9. Директивы IF и IIF предназначены для так называемой трансляции по условию, т. е. для выбора с целью трансляции того или иного блока команд или одиночных команд языка ас- семблера. 10. Директива .NARG используется для определения числа фактических параметров, передаваемых макроопределению при обращении к нему. Директива .NCHR предназначена для при- своения символическому имени значения длины заданной строки в качестве значения, принадлежащего таблице символических имен. 11. Директивы .SHOW и .NOSHOW используют параметры EXPANSIONS и BINARY для управления процессом включения текста команд макрорасширений в листинг, создаваемый транс- лятором языка ассемблера: первый параметр в первой директиве назначает, а во второй отменяет включение в листинг всех ко- манд макрорасширения; второй параметр в первой директиве назначает, а во второй отменяет включение в листинг выполняе- мых команд макрорасширения. Новые директивы .ENDC .IF_FALSE .IRP .NARG .ENDM ,IF_TRUE .IRPC .NOSHOW .ENDR .IF_TRUE_FALSE .MACRO .REPEAT .IF .IIF .MEXIT Новые функции и символы новых операций /(вычисление значения символического имени как адреса) % EXTRACT % LENGTH % LOCATE Новые термины Макрорасширение Трансляция по условию Вопросы и упражнения 1. Чем следует руководствоваться при выборе между под- программами и макросредствами? 2. В чем различие функций, выполняемых директивами .SHOW и .NOSHOW, при использовании параметров BINARY и EXPANSIONS? 3. Что происходит при обращении к макроопределению, ко- личество формальных параметров которого меньше количества фактических параметров макрокоманды, вызывающей это мак- роопределение?
350 Глава 11 4. Что происходит при обращении к макроопределению, ко- личество формальных параметров которого больше количества фактических параметров макрокоманды, вызывающей это мак- роопределение? 5. Какова форма представления фактических параметров, ко- торые заменяют формальные параметры макропределения при обращении к последнему? 6. В чем различие между ключевыми параметрами и прини- маемыми по умолчанию значениями формальных параметров? 7. Какие символы нельзя использовать в качестве ограничи- телей строк, применяемых как фактические параметры макро- команд? 8. Как можно сцепить между собой два параметра, исполь- зуемых в макроопределении? 9. Когда возникает необходимость передать макроопределе- нию значение символического имени в качестве фактического па- раметра? 10. Допустимо ли использование функции % LENGTH за пре- делами макроопределения? 11. Объясните назначение аргументов функции % EXTRACT и действия, выполняемые при их задании. 12. В чем разница действий, выполняемых согласно директи- вам .IRP и .REPEAT? 13. Перечислите и объясните назначение всех возможных операндов директивы .IIF. 14. В каких случаях целесообразно применять директиву •NARG? Напишите на языке ассемблера и выполните отладку макро- определений для решения приводимых ниже задач. 15. Параметры: два целых числа BEGIN и END, а также символическое имя (метка). Искомый результат: макроопределение, формирующее кон- станту размером длинное слово для каждого целого числа, при- надлежащего диапазону значений от BEGIN до END; первая константа должна иметь указанное символическое имя (метку). 16. Параметры: два целых числа BEGIN и END, а также символическое имя. Искомый результат: макроопределение, формирующее коман- ды сохранения содержимого регистров с номерами от BEGIN до END в области памяти с указанным символическим именем. 17. Параметры: два имени FROM и ТО, а также целое число LENGTH. Искомый результат: макроопределение, использующее коман- ды MOVL для пересылки содержимого LENGTH длинных слов из области FROM в область ТО. 18. Параметры: два имени (метки) TEST-VALUE и TARGET.
Макрокоманды 351 Искомый результат: макроопределение, формирующее коман- ду BRW передачи управления по метке TARGET, если содержи- мое слова памяти с именем TEST-VALUE равно нулю. 19. Параметры: имя и целое число. Искомый результат: макроопределение, формирующее коман- ду возведения содержимого длинного слова памяти указанного имени в степень, задаваемую вторым параметром. 20. Параметры: два имени и два целых числа. Искомый результат: макроопределение, формирующее коман- ды для заголовка цикла FOR-ТО путем использования первого имени в качестве переменной цикла, второго имени — как метки, а двух чисел — в качестве начального и конечного значений па- раметра цикла. (Макроопределение должно быть корректным и без предположения о том, что цикл повторяется хотя бы один раз.) 21. Параметры-, четыре имени и знак операции отношения (например, «=», «( и т. п.). Искомый результат: макроопределение, формирующее коман- ды для заголовка цикла WHILE при условии, что первое имя — метка начала цикла, второе имя — метка конца цикла, а остав- шиеся два имени — символические адреса местоположения длин- ных слов памяти, содержимое которых подлежит сравнению,
Глава 12 Команды десятичной арифметики и арифметики чисел с плавающей точкой Помимо команд, предназначенных для выполнения операций над целыми числами, большинство мини-ЭВМ и все большие вычислительные системы располагают командами, манипулирую- щими с десятичными числами и числами, представленными в виде мантиссы и порядка (числа с плавающей точкой). Такое представление позволяет вычислительной машине хранить в па- мяти числа очень широкого диапазона значений, используя в ка- честве хранимой информации только значащие цифры. Вычисли- тельная система VAX имеет команды для выполнения разнооб- разных операций, часто необходимых при обработке чисел с пла- вающей точкой. Десятичные числа хранятся в памяти машины в виде после- довательностей кодов десятичных цифр. Поскольку десятичные числа широко используются в прикладных программах всевоз- можного делопроизводства, любая ЭВМ, предназначенная для этих целей, должна располагать программными средствами опи- сания данных соответствующего типа и командами десятичной арифметики. Вычислительная система VAX, предназначенная как для выполнения нучно-технических расчетов, так и для де- лопроизводства, включает в набор своих команд такие, которые оперируют десятичными числами. 12.1. Числа с плавающей точкой одинарной точности Стандартным для системы VAX является представление чисел с плавающей точкой с одинарной или двойной точностью. В дан- ном разделе рассматриваются формы представления и команды обработки чисел одинарной точности. 12.1.1. Запись числа с плавающей точкой одинарной точности Число с плавающей точкой — это число, представленное в виде мантиссы и порядка 1). Имеются два отличия представления чи- 4 4) Далее в тексте, как правило, подразумевается представление мантиссы в нормализованном виде, т. е. в виде правильной десятичной дроби, содержа- щей первую значащую цифру в разряде десятых долей. — Прим, ред.
Команды для десятичных чисел и чисел с плавающей точкой 353 сел в виде мантиссы и порядка в математике и подобного пред- ставления на языке ассемблера системы VAX. Математическая запись мантиссы предполагает наличие цифры слева от десятич- ной точки (десятичной запятой), представление в машине ман- тиссы числа с плавающей точкой только подразумевает наличие такой цифры, всегда равной нулю. На языке ассемблера систе- мы VAX порядок — это степень числа 2, а не числа 10, как это принято в математике. Ниже приводятся примеры записи чисел в форме плавающей точки с указанием в скобках их эквивален- тов в общепринятой форме. 1.378Е5 (137800) —2.57361Е — 6 (—0,00000257361) Е5 и Е—6 означают 105 и 10“6 соответственно. В большинстве языков программирования для обозначения числа 10 в соответ- ствующей степени используется буква Е, поскольку ни перфора- торы, ни клавиатура терминалов ЭВМ не позволяют осуществ- лять отделение показателя степени (порядка) от ее основания (числа 10) путем смещения показателя вверх. 31 1615 14 7 6 0 Мантисса (младшие разряды) Порядок „с избытком 128*’ Мантисса (старшие разряды) Знак Рис. 12.1. Формат представления числа одинарной точности с плавающей точкой. На рис. 12.1 показано, в какой форме представлено и хра- нится число с плавающей точкой в памяти машины. Несколько необычным выглядит представление мантиссы: она разделена на две части, размещаемые в смежных словах памяти. Выбор такого формата для представления чисел с плавающей точкой объясняется стремлением к совместимости между вычислитель- ными машинами VAX и PDP-11. Самый младший значащий бит двоичного кода мантиссы занимает разряд 16, самый старший — разряд 6. Чтобы лучше понять соотношение указанных частей двоичного представления мантиссы, следует мысленно отделить ее левую часть (младшие разряды), перенести направо и при- соединить разряд 31 левой части мантиссы к разряду 0 правой части. Разряд 15 предназначен для размещения кода (бита) знака': двоичного нуля, если число положительное, и двоичной единицы, если число отрицательное. В разрядах 7—14 размещается поря- док (показатель степени 2). Вместо использования дополнитель- 19 .Чяк 4ЯЯ
354 Глава 12 ного кода для представления порядка как целого числа со зна- ком, применяется запись показателя в виде положительного чис- ла (числа без знака), получаемого путем сложения истинного значения показателя с числом 128. Такое представление порядка условно называют порядком с избытком 128. Для превращения порядка с избытком 128 в первоначальный (естественный) вид необходимо из него вычесть число 128. Например если 8-бито- вый порядок числа с плавающей точкой равен десятичному чис- лу 141, то его действительное значение равно 13; если же поря- док с избытком 128 имеет значение 120, то его истинное значение равно —8. Хотя в 8-разрядном двоичном поле представления порядка можно размещать числа от 0 до 255, двоичный код нуля имеет специальное назначение. Значения порядка с избытком 128, при- надлежащие диапазону от 1 до 255, позволяют представлять истинные значения порядка от —127 до +127. Поскольку у чис- ла с плавающей точкой порядок есть степень числа 2, то числа с плавающей точкой одинарной точности в системе VAX имеют абсолютные значения в пределах диапазона 2~1274-2+127. Для представления мантиссы числа с плавающей точкой оди- нарной точности система VAX использует 24 бита, что эквива- лентно десятичному числу из семи цифр. Однако реально для двоичного кода мантиссы имеется только 23 двоичных разряда. Это противоречие, кажущееся на первый взгляд очевидным, ре- шено разработчиками системы VAX следующим образом. После выполнения любой операции над числами с плавающей точкой осуществляется нормализация результата: у мантиссы отбрасы- ваются так называемые ведущие нули (предшествующие первой значащей цифре), а порядок уменьшается на величину, равную количеству отброшенных нулей. Следствием нормализации яв- ляется наличие в старшем разряде мантиссы двоичной единицы независимо от значения результата, если, конечно, последний не равен нулю. Для мантиссы ненулевых результатов принято хра- нить все двоичные цифры, кроме указанной единицы. Поэтому для размещения мантиссы оказывается достаточным 23 разряда (с 0-го по 6-ой и 15-го по 31-й). Следовательно, разряд 6 со- держит цифру не самого старшего разряда, а следующего за ним. Для получения истинного значения мантиссы к самому старшему разряду ее 23-битового кода нужно присоединить са- мую старшую значащую цифру, всегда равную единице (по- скольку мантисса нормализована). Пусть, например, результат некоторой арифметической операции над числами с плавающей точкой имеет следующий вид: мантисса 000010010011000011011011 (двоичное число) порядок 135 (десятичное число)
Команды для десятичных чисел и чисел с плавающей точкой 355 После нормализации у мантиссы окажутся отброшенными 4 дво- ичных нуля, расположенные слева, а значение порядка будет уменьшено на 4. Убирая самую старшую значащую единицу мантиссы (в дальнейшем наличие этой единицы всегда подразу- мевается), получаем представление числа с плавающей точкой, принятое в системе VAX: мантисса 00100110000110110110000 (двоичное число) порядок 131 (десятичное число) Если мантисса результата операции равна нулю, то и весь ре- зультат равен нулю независимо от знака порядка. Для такого результата в системе VAX предусмотрена определенная стан- дартная форма представления: двоичные нули записываются в разрядах, предназначенных как для мантиссы и порядка, так и для знака. Другим специфическим содержимым поля представления чис- ла с плавающей точкой одинарной точности является наличие нуля в разрядах размещения порядка и единицы в разрядах для мантиссы. Если операнд (участник операции) имеет указанное значение, то операция не выполняется. Такое число с плаваю- щей точкой одинарной точности называют зарезервированным. Ниже приведены двоичные коды нуля и указанного зарезерви- рованного числа соответственно. 00000000 00000000 00000000 00000000 (нуль) 00000000 00000001 00000000 00000000 (зарезервирован- ное число) Рассмотрим процедуру определения значений мантиссы и по- рядка числа с плавающей точкой по ее двоичному коду. Пусть шестнадцатеричная запись кода числа имеет вид 000041F8. Тог- да двоичный код этого числа можно представить следующим образом: 0000 0000 0000 0000 0 100 00011 111 1000 ' • ’ t —•—’——’ мантисса знак порядок мантисса (младшие разряды) (старшие разряды) Знак числа равен 0 (мантисса положительная). Порядок с избытком 128 равен 83ю = 131ю. Порядок равен 131 — 128 = 3. Мантисса равна 0.1111 1000 0000 0000 0000 00002. Число равно произведению мантиссы на 23, т. е. двоичному чис- лу 111.112. В десятичной системе счисления число равно 7 4- у + = 7,75.
356 Глава 12 Аналогично можно описать процедуру преобразования деся- тичного числа в двоичный код этого числа в форме с плавающей точкой или шестнадцатеричный эквивалент этого кода. Пусть исходное десятичное число равно —5,5. Двоичный эквивалент исходного числа равен —101.1. После нормализации двоичный эквивалент числа состоит из мантиссы —0.1011 и порядка 310. Машинное представление величины мантиссы имеет вид: 0.0110 ... 0. Знак числа равен 1. Двоичный код порядка: 112 = (310). Порядок с избытком 128 равен 12810 + 310— 13110= 1000 00112. Двоичный код машинного представления числа имеет следую- щий вид: 0000 0000 0000 0000 1 1000 0011 0 11 0000 Мантисса Знак Порядок Мантисса (младшие разряды) (старшие разряды) Шестнадцатеричный эквивалент двоичного кода числа равен 0000 С1В0. Точность выполнения всех операций над числами одинарной точности в форме мантиссы и порядка лимитирована 24 двоич- ными (7 десятичными) разрядами представления мантиссы. Дей- ствительный диапазон значений десятичных чисел, которые мо- гут быть представлены в такой форме, простирается от 0.29Е—38 до 1.7Е38. Для большинства практических применений такого диапазона допустимых значений чисел вполне достаточно, одна- ко точность представления чисел нередко оказывается неудовле- творительной. Поэтому в системе VAX предусмотрено представ- ление чисел с плавающей точкой двойной точности (см. разд. 12.2). 12.1.2. Запись констант в форме с плавающей точкой Язык ассемблера системы VAX допускает несколько различных форм записи констант с плавающей точкой, а именно [ЗН] СЦ [ЗН] сц.сц [ЗН]СЦ Е[ЗН]СЦ [ЗН] СЦ.Е [ЗН] СЦ [ЗН] СЦ.СЦ Е [ЗН] СЦ
Команды для десятичных чисел и чисел с плавающей точкой 357 где СЦ — строка десятичных цифр, ЗН — знак, [] — условное обозначение того, что указанное в скобках необязательно при- сутствует в записи числа. Примеры использования этих форм записи констант с плавающей точкой: -32. 4.654 45Е-5 4-2.Е27 -2754.3Е + 8 гг Программные средства выделения памяти для переменных в форме с плавающей точкой подобны программным средствам выделения памяти для переменных целого типа. Директива .BLKF резервирует указываемое ее операндами количество об- ластей памяти для размещения чисел с плавающей точкой оди- нарной точности и очищает эти области (присваивает их содер- жимому нулевые значения). Директива .FLOAT (именуемая также .F-FLOATING) по на- значению подобна директиве .LONG. Резервируемым ею обла- стям памяти присваивается содержимое согласно значениям опе- рандов. Именно таковы функции, например, следующих дирек- тив: SUM: .FLOAT 0 . PI: .FLOAT 3.141593 CHARGE: .FLOAT -2.71 E -27 LIST: .BLKF 10 Если число содержит избыточное количество значащих цифр, то при выполнении директивы, в которой такое число указано, осу- ществляется его округление (например, округляется число 3.14159265). Такое округление, выполняемое по умолчанию ди- рективами для чисел с плавающей точкой одинарной точности, можно отменить, поместив в программе директиву .ENABLE TRUNCATION Согласно этой директиве (вместо параметра TRUNCATION ко- торой можно использовать его сокращение FPT) избыточные цифры указанных констант отбрасываются. 12.1.3. Неарифметические операции над числами с плавающей точкой Ряду операций над целыми числами соответствуют аналогичные операции над числами с плавающей точкой. Поэтому для записи команд, выполняющих подобные операции над числами с пла- вающей точкой, необходимо в символических именах кодов опе- раций команд для целых чисел буквы В, W, L, Q заменить на букву F.
358 Глава 12 Так, команда MOVF выполняет над числами с плавающей точкой операции, аналогичные выполняемым командой MOVL над целыми числами размером длинное слово. Единственное раз- личие между этими командами в том, как осуществляется про- верка корректности операндов. Хотя команда MNEGF тоже бе- рет противоположное по знаку значение своего первого операн- да и перемещает по адресу, задаваемому вторым операндом, вы- числение противоположного по знаку значения числа с плаваю- щей точкой существенно отличается от аналогичной обработки целого числа. В первом случае значение содержимого разряда 15 просто меняется на противоположное, во втором случае вычис- ляется дополнительный код («дополнение до двух») целого числа. Действие команды MOVAF подобно действию команды MO- VAL: адрес первого операнда помещается по адресу, указывае- мому вторым операндом команды. В результате трансляции этих команд формируется один и тот же машинный код. Команда TSTF устанавливает то или иное значение битов Z и N признака результата в зависимости от значения числа с пла- вающей точкой, адресуемого операндом команды. Эта команда отличается от команды TSTL, поскольку по-разному представ- ляются адресуемые ими данные. Выполняющая сравнение чисел с плавающей точкой команда CMPF по своим действиям подоб- на команде CMPL. Команда PUSHAF, как и команда MOVAF, преобразуется в результате трансляции в тот же машинный код, что и анало- гичная команда обработки целых чисел размером длинное сло- во, т .е. команда PUSHAL. Вот почему при необходимости за- грузки в стек числа с плавающей точкой можно воспользоваться командой PUSHL. Примеры использования некоторых из описанных команд приведены в разд. 12.1.4. 12.1.4. Арифметические команды чисел с плавающей точкой Эти команды являются модификацией команд арифметики це- лых чисел, символические имена кодов операций которых необ- ходимо изменить так, чтобы они завершались буквой F. Команда CLRF присваивает нулевое значение своему операн- ду. Это значение имеет ту же форму представления, что и рав- ное нулю целое число размером длинное слово. В результате трансляции команд CLRF и CLRL формируется один и тот же машинный код. Команды ADDF2 и ADDF3 осуществляют сложение чисел с плавающей точкой одинарной точности; первая команда поме- щает результат на место своего второго операнда, вторая коман-
Команды для десятичных чисел и чисел с плавающей точкой 359 да размещает результат по адресу, задаваемому ее третьим операндом. Команды SUBF2 и SUBF3 являются соответственно двух- и трехоперандными командами вычитания чисел с плавающей точ- кой одинарной точности. Команды MULF2 и MULF3 — двух- и трехоперандные команды умножения подобных чисел, DIVF2 и DIVF3 — аналогичные двух- и трехоперандные команды деле- ния. Отметим, что если делитель равен нулю, то результат вы- полнения той или иной из двух последних команд непредска- зуем. Результаты всех операций над числами с плавающей точкой одинарной точности округляются, если мантисса содержит более 24 значащих битов. Все операции над числами с плавающей точ- кой воздействуют на биты-индикаторы признака результата так же, как операции над целыми числами. Поэтому все рассмотрен- ные выше команды условной передачи управления, используемые после команд, выполняющих операции над целыми числами, применимы после команд операций над числами с плавающей точкой. Константы с плавающей точкой можно использовать в каче- стве операндов команд, выполняющих операции над числами с плавающей точкой. Подобно их целочисленным аналогам эти константы можно представлять в так называемой непосредствен- ной форме или форме короткого литерала. Транслятор языка ассемблера сам выбирает форму представления константы, если форма не задана (см. гл. 15). Отличительным признаком зада- ния операнда в виде константы с плавающей точкой является наличие в поле операнда команды перед таким числом знака «#», как показано в следующем примере: MOVF #4.32, RESULT ADDF2 #- 10.632, SUM Иногда в качестве переменной (параметра) цикла, управляе- мого счетчиком, используется переменная, принимающая значе- ния чисел с плавающей точкой. Это имеет место, когда перемен- ная цикла применяется в операциях над числами с плавающей точкой или когда такая переменная должна получать нецелочис- ленные приращения. В языке Паскаль операции положительного или отрицательного приращения параметра цикла FOR могут выполняться только, если этот параметр и приращения — целые числа. В предложенном в данной книге псевдокоде понятие цик- ла FOR обобщается на случай переменной цикла, принимающей значения чисел с плавающей точкой. Такие циклы легко про- граммируются на языке ассемблера системы VAX посредством
360 Глава 12 команды АСВлс, модификация которой для работы с числами с плавающей точкой одинарной точности имеет вид ACBF. Пример использования этой команды в так называемой скелетной схеме цикла приводится ниже. Д Пример 12.1. Использование команды ACBF \ ДЛЯ VAR: = 0.0 ДО 1.5 С ШАГОМ 0.1 ВЫПОЛНЯТЬ ; В ЦИКЛЕ MOVF #0.0, VAR LOOP: ACBF #1.5, #0.1, VAR, LOOP ; КОНЕЦ ЦИКЛА «ДЛЯ» При первом выполнении команд тела цикла переменная VAR (параметр цикла) имеет значение 0,0, при втором выполнении — 0,1, при третьем — 0,2 и так далее до тех пор, пока не произой- дет выполнение операторов тела цикла при значении этой пере- менной, равной 1,5. Следует помнить, что проблемы, присущие операциям над числами с плавающей точкой при программировании на языке ассемблера системы VAX, носят тот же характер, что и подоб- ные проблемы при программировании на языках Фортран и Па- скаль. Так, например, запись числа в форме с плавающей точ- кой позволяет представлять числовые значения только прибли- женно. Десятикратное добавление числа 0,1 в форме с плаваю- щей точкой необязательно дает результат, равный 1,0, поскольку имеют место ошибки округления. Часто возникает необходимость включать целые числа в арифметические выражения, описывающие операции над числа- ми с плавающей точкой. В языках высокого уровня таких, как Фортран или Паскаль, целые числа, используемые в таких ариф- метических выражениях, автоматически преобразуются в числа с плавающей точкой. У многих начинающих программистов соз- дается впечатление, что вычислительные машины могут опериро- вать числами разных типов (один операнд — целое число, дру- гой— число с плавающей точкой и т. п.). Однако смешение ти-
Команды для десятичных чисел и чисел с плавающей точкой 361 пов операндов в одной и той же операции недопустимо. Арифме- тические команды выполняют операции либо только над целыми числами и формируют результат в виде целого числа, либо только над числами с плавающей точкой, создавая результат того же типа. Система VAX располагает полным набором ко- манд преобразования целых чисел в числа с плавающей точкой и обратно. Команды CVTBF, CVTWF и CVTLF преобразуют задаваемые их первыми операндами целые числа размером байт, слово или длинное слово соответственно в числа с плавающей точкой оди- нарной точности, которые размещаются в полях, адресуемых вторыми операндами этих команд. Целые числа размером байт и слово, содержащие не более трех или пяти цифр соответствен- но, преобразуются точно, без ошибок, поскольку мантисса числа с плавающей точкой одинарной точности представляется семью десятичными цифрами. Целые числа размером длинное слово могут содержать до десяти десятичных цифр и, следовательно, количество значащих цифр подлежит округлению до семи в ре- зультате преобразования такого целого числа. В системе VAX имеются команды преобразования чисел с плавающей точкой одинарной точности в целые числа. Команды CVTFB, CVTFW и CVTFL преобразуют задаваемые их первыми операндами числа с плавающей точкой в целые числа размером байт, слово и длинное слово соответственно, которые разме- щаются в полях, адресуемых вторыми операндами этих команд. В тех случаях, когда число с плавающей точкой содержит боль- ше значащих цифр, чем их может разместиться в поле, предо- ставляемом для результата преобразования — целого -числа, «лишние» цифры (цифры младших разрядов) отбрасываются. Если поле размещения результата преобразования имеет размер длинного слова, то число с плавающей точкой, преобразуемое в целое число, может быть округлено так, что целочисленный ре- зультат будет содержать не более 10 цифр. Для этих целей ис- пользуется команда CVTRFL, выполняющая преобразование с округлением числа с плавающей точкой одинарной точности в целое число размером длинное слово. После рассмотрения большинства команд системы VAX, опе- рирующих с числами с плавающей точкой одинарной точности, можно перейти к описанию их применения в программе. До сих пор осталась не рассмотренной техника формирования макро- средств ввода чисел с плавающей точкой в систему VAX, и вы- вода из нее посредством терминала или путем обращения к фай- лу на магнитном диске. В приводимом ниже примере использу- ется подпрограмма для демонстрации применения операций над числами с плавающей точкой. Формирование процедур ввода и вывода чисел с плавающей точкой описывается в гл. 14.
362 Глава 12 А Пример 12.2 • Постановка задачи Исходные данные: число с плавающей точкой Искомый результат: значение синуса исходного числа, запи- санное в регистре R0 Предлагается для решения этой задачи написать подпро- грамму-функцию. Для вычисления значения синуса как функции заданного аргумента воспользуемся разложением такой функции в ряд Тейлора. Поскольку в системе VAX представление чисел с плавающей точкой одинарной точности ограничено семью стар- шими значащими цифрами, последнее можно использовать в ка- честве критерия окончания итерационного процесса вычисления суммы членов указанного выше ряда. Формула, описывающая разложение искомой тригонометриче- ской функции в ряд Тейлора, имеет следующий вид: SINx = х - х3/3! + х5/5! - х7/7! + ... В результате суммирования достаточного числа членов такого ряда можно получить значение синуса с требуемой точностью. Количество слагаемых, подлежащих суммированию, не является постоянным числом при заданной точности вычисления, а зави- сит от значения аргумента этой функции. Максимальная ошибка вычисления определяется абсолютным значением первого из сла- гаемых, не включенных в сумму («отброшенных»). Если абсо- лютное значение «отброшенного» слагаемого меньше, чем 0,000001, то можно считать, что искомая функция вычислена с ошибкой, по крайней мере меньшей, чем 0,000001. Отметим, что для вычисления значения синуса разложение этой тригонометрической функции в ряд Тейлора нельзя считать наилучшим решением; однако такой подход позволяет наглядно продемонстрировать применение на практике арифметических операций над числами с плавающей точкой. Используемые в приведенной выше формуле восклицательные знаки символизируют хорошо известную математическую функ- цию — факториал. Вычисление этой функции как произведения натуральных (целых положительных) чисел определяется сле- дующей рекурсивной формулой: FACTORIAL(N) = N • FACTORIAL^ - 1) где FACTORIAL(O) == FACTORIAL(l) = 1 Несмотря на определение факториала как рекурсивной функции, при решении рассматриваемой задачи факториал предлагается вычислять методом итераций посредством подпрограммы-функ- ции. Отметим, что при вычислении факториала операции выпол-
Команды для десятичных чисел и чисел с плавающей точкой 363 няются над целыми числами, целым числом является и резуль- тат. Однако последний слишком быстро (уже при сравнительно небольших значениях аргумента) становится очень большим чис- лом. Поэтому в программе значение факториала представляется числом с плавающей точкой. Главным элементом подпрограммы вычисления синуса явля- ется цикл суммирования слагаемых ряда, в который разлагается искомая тригонометрическая функция. Ниже приводится подпро- грамма вычисления синуса, написанная на псевдокоде. • Алгоритм решения задачи на псевдокоде Присвоить SIGN значение —1 Присвоить SINE значение X Присвоить NEW-TERM значение —Х3/3! Присвоить POWER значение 3 WHILE абсолютное значение NEW-TERM > 0.000001 DO Добавить NEW-TERM к SINE Присвоить SIGN значение — 1 * SIGN Добавить 2 к POWER Присвоить NEW-TERM. значение SIGN * Xpower/POWERI END-DO Добавить NEW_TERM к SINE Конец алгоритма Искомая сумма — значение синуса (при заданном значении аргумента) — состоит из знакопеременных слагаемых. Этим объ- ясняется включение в тело цикла переменной SIGN, величина которой постоянна и равна 1, а знак меняется при каждом по- вторении операций тела цикла. ® Программа на языке ассемблера ; ПОДПРОГРАММА - ФУНКЦИЯ ВЫЧИСЛЕНИЯ СИНУСА ; ПАРАМЕТР: ЧИСЛО С ПЛАВАЮЩЕЙ ТОЧКОЙ ; ОДИНАРНОЙ ТОЧНОСТИ ; ИСКОМОЕ ЗНАЧЕНИЕ ФУНКЦИИ: СИНУС ИСХОДНОГО ; ЧИСЛА (ПАРАМЕТРА), ; РАЗМЕЩАЕМЫЙ В РЕГИСТРЕ R0 (ПАРАМЕТР - ЭТО ; УГОЛ В РАДИАНАХ) .ENTRY SINE, ^M(R2) ARG = 4
364 Глава 12 ; ПРИСВОЕНИЕ SIGN ЗНАЧЕНИЯ - 1, ; SINE ЗНАЧЕНИЯ ARG, POWER ЗНАЧЕНИЯ 3 MOVF #-1.0, SIGN MOVF ARG(AP), SINE-VALUE MOVF #3.0, POWER ; ВЫЧИСЛЕНИЕ ВТОРОГО СЛАГАЕМОГО И ПРИСВОЕНИЕ ; NEW.TERM ЭТОГО ЗНАЧЕНИЯ ; (— ARG**3/3!) PUSHL POWER CALLS # 1, FACTORIAL MULF3 ARG(AP), ARG(AP), R2 MULF2 ARG(AP), R2 MNEGF R2, R2 DIVF3 R0, R2, NEW-TERM ; ПРИСВОЕНИЕ ABS-NEW-TERM АБСОЛЮТНОГО ЗНАЧЕНИЯ ; NEW-TERM MOVF NEW-TERM, ABS_NEW_TERM ’ЕСЛИ NEW^TERM <0 TSTF NEW-TERM BGEQ LOOP ; TO СДЕЛАТЬ ЕГО ПОЛОЖИТЕЛЬНЫМ MNEGF ABS_NEW_TERM, ABS_NEW_TERM КОНЕЦ ОПЕРАЦИИ «ЕСЛИ» ; ПОКА ABS_NEW_TERM > 0.000001 ВЫПОЛНЯТЬ В ЦИКЛЕ LOOP: CMPF ABS-NEW-TERM, #0.000001 BGTR IN_LOOP BRW END-DO IN-LOOP; • ДОБАВИТЬ К SINE_VALUE ЗНАЧЕНИЕ NEW-TERM, ADDF2 NEW-TERM, SINE-VALUE ; ПРИСВОИТЬ SIGN ЗНАЧЕНИЕ - 1, УВЕЛИЧИТЬ ЗНАЧЕНИЕ ; POWER НА 2
Команды для десятичных чисел и чисел с плавающей точкой 365 MULF2 #-1.0, SIGN ADDF2 #2.0, POWER 6 ; ПРИСВОИТЬ NEW-TERM ЗНАЧЕНИЕ ; SIGN * ARG ** POWER / POWER! PUSHL ARG(AP) PUSHL POWER CALLS #2, EXP MOVF RO. R2 PUSHL POWER CALLS #1, FACTORIAL MULF2 SIGN, R2 DIVF3 RO, R2, NEW-TERM ; ПРИСВОИТЬ ABS-NEW-TERM АБСОЛЮТНОЕ ЗНАЧЕНИЕ ; NEW-TERM MOVF NEW-TERM, ABS_NEW_TERM ; ЕСЛИ NEW-TERM <0 TSTF NEW-TERM BGEQ OK ; TO СДЕЛАТЬ ABS-NEW-TERM ПОЛОЖИ- ТЕЛЬНЫМ MNEGF ABS_NEW-TERM, ABS-NEW-TERM ; КОНЕЦ ОПЕРАЦИИ «ЕСЛИ» OK: BRW LOOP ; КОНЕЦ ЦИКЛА «ПОКА» ; ДОБАВЛЕНИЕ ПОСЛЕДНЕГО СЛАГАЕМОГО К ИСКОМОЙ ; СУММЕ И ПЕРЕДАЧА УПРАВЛЕНИЯ ВЫЗЫВАВШЕМУ ПРОГРАММ- ; НОМУ МОДУЛЮ END-DO: ADDF2 NEW-TERM, SINE-VALUE, R0 RET ; ОБЛАСТИ ПАМЯТИ ДЛЯ ДАННЫХ ПРОГРАММЫ SIGN; .BLKF 1 ; МНОЖИТЕЛЬ, МЕНЯЮЩИЙ ЗНАК ; ОЧЕРЕДНОГО СЛАГАЕМОГО
366 Глава 12 NEW-TERM: .BLKF 1 ; ОЧЕРЕДНОЕ СЛАГАЕМОЕ SINE_VALUE: .BLKF 1 ; ТЕКУЩЕЕ ЗНАЧЕНИЕ СУММЫ POWER: .BLKF 1 ; ПОКАЗАТЕЛЬ СТЕПЕНИ ; АРГУМЕНТА X ABS_NEW_TERM: .BLKF 1 ; АБСОЛЮТНОЕ ЗНАЧЕНИЕ ; ОЧЕРЕДНОГО СЛАГАЕМОГО ; КОНЕЦ ПОДПРОГРАММЫ • ПОДПРОГРАММА FACTORIAL ; ПАРАМЕТР: ЧИСЛО С ПЛАВАЮЩЕЙ ТОЧКОЙ ; ОДИНАРНОЙ ТОЧНОСТИ ;ИСКОМОЕ ЗНАЧЕНИЕ ФУНКЦИИ: ФАКТОРИАЛ ; ИСХОДНОГО ЧИСЛА, РАЗМЕ- ; ЩАЕМЫИ В РЕГИСТРЕ .ENTRY FACTORIAL, О ARG = 4 MOVF #1.0, RESULT ; ДЛЯ COUNT: = 2 ДО ARG ВЫПОЛНЯТЬ В ЦИКЛЕ MOVF #2.0, COUNT CMPF COUNT, ARG(AP) BLEQ F-LOOP BRW OUT_F_LOOP F_LOOP: ; ДОМНОЖЕНИЕ RESULT НА ОЧЕРЕДНОЙ ; СОМНОЖИТЕЛЬ MULF2 COUNT, RESULT ACBF ARG(AP), # 1.0, COUNT, F_LOOP • КОНЕЦ ЦИКЛА «ДЛЯ» ; ЗАГРУЗКА RESULT В R0 И ВОЗВРАТ УПРАВЛЕНИЯ ; ВЫЗЫВАВШЕМУ МОДУЛЮ OUT-F-LOOP: MOVF RESULT, RO RET • ОБЛАСТИ ПАМЯТИ ДЛЯ ДАННЫХ ПОДПРОГРАММЫ FACTORIAL RESULT: .BLKF 1 ; ТЕКУЩЕЕ ЗНАЧЕНИЕ
Команды для десятичных чисел и чисел с плавающей точкой Зв7 ; ФАКТОРИАЛА COUNT: .BLKF 1 ; СЧЕТЧИК ЦИКЛА ВЫЧИСЛЕНИЯ ; ФАКТОРИАЛА ; КОНЕЦ ПОДПРОГРАММЫ FACTORIAL ; ПОДПРОГРАММА ЕХР ; ПАРАМЕТРЫ: ; 1) ПОКАЗАТЕЛЬ СТЕПЕНИ В ФОРМЕ ЧИСЛА ; С ПЛАВАЮЩЕЙ ТОЧКОЙ ОДИНАРНОЙ ТОЧНОСТИ ; 2) ОСНОВАНИЕ СТЕПЕНИ В ФОРМЕ ЧИСЛА ; С ПЛАВАЮЩЕЙ ТОЧКОЙ ОДИНАРНОЙ ТОЧНОСТИ ; ИСКОМОЕ ЗНАЧЕНИЕ ФУНКЦИИ: ОСНОВАНИЕ ; VALUE, ВОЗВЕДЕННОЕ В СТЕПЕНЬ, РАВНУЮ ; ЦЕЛОЧИСЛЕННОМУ ЗНАЧЕНИЮ ПОКАЗАТЕЛЯ .ENTRY ЕХР, О EXPONENT =4 VALUE =8 MOVF VALUE(AP); RO ; ДЛЯ COUNTER: =2 ДО EXPONENT ВЫПОЛНЯТЬ ;В ЦИКЛЕ MOVF #2.0, COUNTER CMPF COUNTER, EXPONENT(AP) BLEQ E_LOOP BRW OUT_E_LOOP E-LOOP: • ДОМНОЖЕНИЕ RESULT HA VALUE MULF2 VALUE(AP), RO ACBF EXPONENT(AP), # 1.0, COUNTER, E_LOOP ; КОНЕЦ ЦИКЛА «ДЛЯ» ; ВОЗВРАТ УПРАВЛЕНИЯ ВЫЗЫВАВШЕМУ ПРОГРАММНОМУ ; МОДУЛЮ OUT_E_LOOP: RET ; ОБЛАСТЬ ПАМЯТИ ДЛЯ ДАННЫХ ПОДПРОГРАММЫ ЕХР COUNTER: .BLKF 1 ; СЧЕТЧИК ЦИКЛА ; КОНЕЦ ПОДПРОГРАММЫ ЕХР
368 Глава 12 В наборе команд языка ассемблера системы VAX имеется еще одна команда арифметики чисел с плавающей точкой, сим- волическое имя кода операции которой — POLYF. Это сложная и мощная (по составу выполняемых операций) команда обеспе- чивает вычисление многочлена по схеме Горнера, используя ми- нимальное число арифметических операций. Команда POLYF имеет обобщенную форму POLYF аргумент, степень, адрес „таблицы ..коэффициентов и предназначена для вычисления значения многочлена как функ- ции одной переменной вида f (х) = а0 + а, • х + а2 • х2 + а3 • х3 + ... + а, • х1 + ... где at — некоторые постоянные коэффициенты, х— переменная (аргумент функции). При использовании команды POLYF ука- занные коэффициенты и переменные должны быть данными од- ного и того же типа. Первый операнд рассматриваемой команды — аргумент вы- числяемой функции, который задается в виде некоторой пере- менной. Второй операнд команды — степень вычисляемого мно- гочлена, равная наибольшему значению показателя степени пе- ременной среди всех слагаемых многочлена. Степени многочлена как операнду команды POLYF должно соответствовать в про- грамме целое число размером слово. Третий операнд команды — адрес таблицы коэффициентов — представляется в виде упоря- доченного списка коэффициентов слагаемых многочлена, начи- ная с коэффициента при аргументе в наивысшей степени. Резуль- тат записывается в регистр R0. Пусть требуется вычислить значение следующего многочлена: f (х) = 5,63 + 2,79 • х + 12,13 • х2 - 0,32 • х3. Тогда для выполнения команды POLYF необходима таблица вида COEF.TAB: .FLOAT —0.32 .FLOAT 12.13 ♦FLOAT 2.79 .FLOAT 5.63 При наличии такой таблицы для вычисления многочлена доста- точно одной команды POLYF X, #3, COEF-TAB
Команды для десятичных чисел и чисел с плавающей точкой 369 12.2. Числа с плавающей точкой двойной точности Числа с плавающей точкой одинарной точности могут содержать не более семи значащих цифр. Если требуется большее количе- ство цифр для представления числовой величины, используют числа с плавающей точкой двойной точности. Для применяемых в научно-технических расчетах языков высокого уровня таких, как Фортран, характерно наличие двух форм представления чи- сел с плавающей точкой. 161514 7 6 О Мантисса (младшие разряды) Мантисса . (средние разряды) Знак Мантисса (старшие разряды) Порядок „Р избытком* 128 ** Рис. 12.2. Формат представления числа двойной точности с плавающей точкой. На рис. 12.2 показана обобщенная форма, в которой пред- ставляются и хранятся в памяти системы VAX числа с плаваю- щей точкой двойной точности. Эта форма является простым рас- ширением формы представления и хранения в памяти машины чисел с плавающей точкой одинарной точности: для размещения мантиссы отводится еще два дополнительных слова, присоеди- няемых к полю представления числа одинарной точности. Наи- меньший значащий бит мантиссы занимает разряд 0 последнего (крайнего слева) слова, а наибольший значащий бит — разряд 6 первого (крайнего справа) слова. Хотя диапазон значений чисел двойной точности остается тем же самым, как и у чисел одинар- ной точности, количество значащих цифр может достигать 16, а следовательно, возрастает и точность представления чисел. Для выделения памяти с целью размещения чисел с двойной точностью используется директива .BLKD, являющаяся разно- видностью директивы .BLKx Количество двойных длинных слов, резервируемых этой директивой, равно значению ее операнда, причем содержимому этих слов присваиваются нулевые значе- ния. О том, что число с плавающей точкой двойной точности равно нулю, указывается так же, как и в случае числа одинар- ной точности, т. е. директива .BLKD вызывает выполнение той же операции, что и директива .BLKQ.
370 Глава 12 Чтобы выделить одну или несколько областей памяти для чисел двойной точности и присвоить этим областям значения данных чисел, применяется директива .DOUBLE или ее эквива- лент— директива .D-FLOATING. Константы двойной точности указываются так же, как и кон- станты одинарной точности, только вместо буквы Е перед значе- нием порядка записывается буква D. Описанные выше директивы иллюстрируют следующие при- меры: SUM: .DOUBLE 1.24625 D -4, -0.00005683, — 4.257D 5 [6] LIST: .BLKD 100 SUM — адрес первой из восьми областей памяти для чисел двой- ной точности, содержимому которой присваивается 0.000124625; второй области, смежной с SUM, присваивается — 0.00005683; каждой из последних шести указанных областей присваивается 425700. LIST — адрес первой из ста 8-байтовых областей, со- держимому каждой из которых присваивается нулевое значение. Команды, выполняющие операции над числами с плавающей точкой двойной точности, подобны командам, оперирующим с числами одинарной точности, и поэтому далее они описываются весьма кратко. Команды ADDx2, ADDx3, SUBx2, SUBx3, DIVx2, DIVx3, MULx2, MULx3, MOVx, CLRx, MNEGx, CMPx, PUSHAx, TSTx, MOVAx имеют соответствующие модификации для операций над числами двойной точности, получаемые под- становкой в символические имена перечисленных кодов операций вместо х буквы D. Аналогично существуют «D-модификации» и для команд АСВх и POLYx, а также семейства команд CVTxx, преобразующих целые числа размером байт, слово, длинное сло- во и числа с плавающей точкой одинарной точности (для чего указываются буквы В, W, L и F соответственно) в числа с пла- вающей точкой двойной точности (буква D) и обратно. Наконец команда CVTRDL округляет значение числа двойной точности таким образом, чтобы оно могло разместиться в области памяти размером длинное слово. В системе VAX имеется возможность дополнения средств представления чисел с плавающей точкой еще двумя формами, именуемыми G и Н. Первая форма (G) предусматривает размещение числа в восьми байтах, обеспечивает несколько меньшую точность пред- ставления, чем в случае чисел двойной точности, но имеет суще- ственно больший диапазон значений порядка. При использова- нии этой формы представления чисел с плавающей точкой ко- личество значащих цифр может достигать 15 при диапазоне значений чисел от 0.56Е—308 до 0.9Е308.
Команды для десятичных чисел и чисел с плавающей точкой 371 Другая форма представления (Н) требует для числа 16 байт памяти, обеспечивает высокую точность и громадный диапа- зон значений порядка. Она позволяет сохранить до 33 знача- щих цифр числа, значение которого принадлежит диапазону от 0.84Е—4932 до 0.59Е4932. Команды, оперирующие числами с пла- вающей точкой в форме G или Н, подобны описанным выше командам для операций над числами одинарной и двойной точ- ности, однако значительно уступают им в быстродействии. Это объясняется не только тем, что они манипулируют операндами больших размеров, но и тем, как их выполняет машина. Они реализуются не аппаратными, а микропрограммными средствами и не используют так называемый акселератор операций с пла- вающей точкой системы VAX. В последующих моделях вычис- лительных машин серии VAX возможна реализация этих команд аппаратно. 12.3. Операции над десятичными числами Часто при использовании ЭВМ необходимо точное выполнение арифметических операций над разнообразными числовыми дан- ными без предъявления повышенных требований к быстродей- ствию. В эту категорию входит большинство финансово-эконо- мических расчетов, которые манипулируют денежными суммами, требующими точного представления их значений при не столь обширных операциях с ними. Большинство операций делопроиз- водства требуют, однако, выполнения процедур ввода и вывода данных. Программы подобного назначения пишутся обычно на языке Кобол. Вычислительные машины, для которых предусмотрено наличие транслятора этого языка, обычно располагают коман- дами операций над десятичными числами, а следовательно, и соответствующими форматами представления таких данных. По- скольку операции над десятичными числами находят примене- ние не только в делопроизводстве, одна из возможных подобных прикладных задач рассматривается далее, после описания фор- матов представления десятичных данных и команд, оперирую- щих этими данными. 12.3.1. Форматы десятичных данных В системе VAX для представления десятичных чисел исполь- зуется несколько форматов, одни из которых пригодны только для ввода и вывода данных, а другие могут применяться для представления числовых значений операндов команд десятич- ной арифметики.
372 Глава 12 Строки неупакованных десятичных цифр в коде ASCII, т. е. последовательности цифр, каждая из которых занимает 1 байт, называются числовыми. В памяти они размещаются не так, как целые числа, т. е. не в обратном порядке расположения байтов. Напротив, первый байт числовой строки, содержащий цифру, яв- ляется «носителем» самой старшей значащей цифры. В системе VAX различают две разновидности числовых строк: с раздель- ным ведущим знаком и ведомым знаком. В числовой строке с раздельным ведущим знаком байт знака предшествует байту, содержащему самую старшую значащую цифру. Содержимым байта знака может быть код ASCII знака «+» (плюс) или «—» (минус), либо пробела; шестнадцатерич- ная запись этих кодов имеет вид 2В, 2D и 20 соответственно. Наличие в байте знака кода пробела (20) эквивалентно указа- нию о том, что число является положительным. Шестнадцате- ричная запись кодов ASCII десятичных цифр 0,1, 2, ..., 9 имеет следующий вид: 30, 31, 32, ..., 39. На основании этого и ис- пользуя представление десятичного числа в виде числовой строки с раздельным ведущим знаком, числа —27 и 341 можно записать в виде 2D3237 и 2В333431 соответственно. Во всех программах, рассмотренных в предыдущих главах и разделах, исходные числовые данные, вводимые в машину по- средством макрокоманды READx, представлены в форме число- вых строк с раздельным ведущим знаком. В разд. 12.3.3 описы- вается преобразование такой формы представления числовых данных в другие, более приемлемые для манипуляций с чис- лами. Операнд, значением которого является числовая строка с раз- дельным ведущим знаком, должен быть задан путем указания адреса байта знака и длины строки (количества содержащихся в ней цифр без учета знака). Например, длины строк 2D3237 и 2В333431 равны 2 и 3 соответственно. Длина строки не должна выходить за диапазон значений 0—31. В числовой строке с ведомым знаком он совмещается с по- следней цифрой строки. Если число — положительное, знак может быть опущен. Отметим, что такая форма без знака от- личается от формы представления с раздельным ведущим знаком, поскольку в последнем случае наличие знака обя- зательно. Для числовых строк с ведомым знаком возможны два ва- рианта задания знака: в так называемом зонном формате 1 и зонном формате 2. В обоих случаях все цифры числовой строки, кроме самой младшей значащей цифры, представляются в коде ASCII. Ниже приведены шестнадцатеричные записи всех воз- можных вариантов кодирования последней цифры совместно со знаком для числовой строки с ведомым знаком.
Команды для десятичных чисел и чисел с плавающей точкой 373 Десятичные цифры со знаком Математическая запись В зонном формате 1 В зонном формате 2 +0 30 7В +1 31 41 +2 32 42 -из 33 43 +4 34 44 +5 35 45 +6 36 46 +7 37 47 +8 38 48 +9 39 49 -0 70 7D -1 71 4А —2 72 4В -3 73 4С —4 74 4D -5 75 4Е -6 76 4F —7 77 50 -8 78 51 -9 79 52 Для представления числовой строки с ведомым знаком не тре- буется отдельный байт для знака. Поэтому значение длины та- кой строки равно числу байтов, занимаемых этой строкой. Две команды системы VAX, оперирующие с числовыми строками с ведомым знаком, применимы при использовании любого из указанных зонных форматов. Для хранения десятичных данных в системе VAX применяет- ся еще один формат их представления, называемый десятичным упакованным. В этом случае две цифры занимают 1 байт. В по- следнем полубайте размещается знак. Хотя обычно для коди- рования знака плюс («+») используется шестнадцатеричная цифра С, а знака минус («—») — цифра D, допустимо примене- ние цифр А, Е и F для кодирования знака «+», а цифры В — для знака «—».
374 Глава 12 Длина строки упакованных десятичных цифр определяется как количество ее цифр без учета знака. Если количество цифр в строке — число четное, то для размещения знака не остается места (свободного полубайта). Поэтому в таком случае к самой старшей значащей цифре добавляется 0. В соответствии с из- ложенным выше десятичные числа 531, —27 и 6315 представ- ляются в виде следующих строк упакованных десятичных цифр: 531С, 027D и 06315С. Если строка упакованных десятичных цифр (упакованные десятичные данные) имеет длину, равную 0, то это означает, что она представлена одним байтом с кодом знака в правом полубайте и кодом нуля в левом, как, например, строка ОС. Для формирования упакованной десятичной константы можно воспользоваться директивой .PACKED. Иногда желательно за- давать длину такой константы не числом, а символическим име- нем переменной. Такая возможность в указанной директиве предусмотрена. Обобщенная форма этой директивы имеет сле- дующий вид: [метка] .PACKED десятичная_строка [, имя] Операнд десятичная_строка может содержать от 0 до 31 деся- тичных цифр, перед которым возможно наличие знака. Если опе- ранд имя используется, то служит для указания длины констан- ты (количества составляющих ее цифр). Отметим, что в каче- стве операнда нельзя применять строку упакованных десятич- ных цифр в виде литерала. Во втором из приводимых ниже примеров использовано имя LEN_CASH и подразумевается, что ему присвоено значение, равное 3. DEBT .PACKED -5631 CASH .PACKED 956, LEN.CASH В то время как целые числа размером длинное слово разме- щаются в смежных байтах памяти в обратном порядке следо- вания пар цифр по старшинству, упакованные десятичные дан- ные обеспечивают естественный порядок чередования значащих цифр с обратным следованием полубайтов внутри каждого байта. Например, значение переменной DEBT представляется в памяти как 1D6305. Полубайты записываются в память па- рами, что и создает представление об обратном порядке их сле- дования. 12.3.2. Команды десятичной арифметики В системе VAX количество команд, оперирующих десятичными данными, ограничено; почти все они выполняют действия с упа- кованными десятичными данными.
Команды для десятичных чисел и чисел с плавающей точкой 375 Пересылку десятичных строк выполняет команда MOVP сле- дующей обобщенной формы: MOVP длина, операнд-источник, операнд-приемник Операнд длина задает количество цифр (не считая знака)', ко- торое содержит пересылаемая строка; это количество указы- вается как целое число размером слово. Операнд-источник и операнд-приемник определяют соответствующие адреса памяти. Отметим, что эта команда использует регистры R0—R3 в каче- стве указателей адресов и счетчиков. Следовательно, в резуль- тате выполнения команды предыдущее содержимое этих реги- стров уничтожается. В приводимом ниже примере строка упа- кованных десятичных цифр с адресом SALARY перемещается в область памяти с адресом RAYROLL. Д Пример 12.3. Применение команды MOVP SALARY: .PACKED 18520 PAYROLL: .BLKB 3 MOVP #5, SALARY, PAYROLL Имеются также команды для выполнения четырех основных арифметических операций над упакованными десятичными дан- ными: для операций сложения и вычитания — двух- и трехопе- рандные команды, для операций умножения и деления — только трехоперандные. Как и в случае команды MOVP для задания одного операнда, адресующего строку упакованных десятичных цифр, в действительности требуются два операнда, один из ко- торых определяет адрес, а другой длину этой строки. Поэтому форматом команд сложения и вычитания предусмотрено 4 или 6 полей для соответствующих операндов. Команды сложения упакованных десятичных данных имеют следующие форматы: ADDP4 длина_слагаемого, адрес-Слагаемого, длина.суммы, адрес _суммы ADDP6 длина_слагаемого_1, адрес-слагаемого длина-Слагаемого-2, адрес_слагаемого_2, длина.суммы, адрес_суммы Согласно команде ADDP4 упакованные десятичные данные ука- занного местоположения и заданной длины добавляются к дан- ным того же типа, адресуемым операндом адрес-суммы и имею- щим длину, указываемую операндом длина-суммы. По команде
376 Глава 12 ADDP6 задаваемые подобным же образом данные (слагаемое 1 и слагаемое 2) суммируются и записываются в область памяти, адресуемую операндом адрес-суммы и имеющую длину, кото- рая указывается операндом длина_суммы. Если адресуемая опе- рандом-приемником область оказывается недостаточной для раз- мещения суммы, фиксируется переполнение и биту V признака результата присваивается значение 1. Значение битов Z и N при- знака результата определяется значением суммы. В результате выполнения команд ADDP4 и ADDP6 уничтожается предыдущее содержимое регистров R0—R3 и R0—R5 соответственно. Две команды вычитания упакованных десятичных данных по- добны рассмотренным командам сложения и имеют следующие форматы: SUBP4 длина-вычитаемого, адрес-вычитаемого, длина_разности, адрес-разности SUBP6 длина-вычитаемого, адрес-вычитаемого, длина-уменьшаемого, длина-разности, адрес-разности Согласно команде SUBP4, упакованные десятичные данные, за- даваемые операндами длина-вычитаемого и адрес-вычитаемого, вычитаются из данных того же типа, задаваемых операндами длина-разности и адрес-разности. По команде SUBP6 данные, задаваемые первой парой операндов, вычитаются из данных, за- даваемых второй парой операндов, а результат записывается в область памяти, определяемую третьей парой операндов. Как и в случае команд ADDPx, в результате выполнения команд SUBP4 и SUBP6 уничтожается содержимое регистров R0—R3 и R0—R5 соответственно. Результаты выполнения этих команд оказывают такое же воздействие на биты N, Z и V, как и команды вычитания целых чисел. Команды деления и умножения упакованных десятичных данных имеют следующие форматы: DIVP длина-делителя, адрес-делителя, длина-делимого, адрес-делимого, длина-частного, адрес-частного MULP длина-множителя, адрес-множителя, длина _мно- жимого, адрес-множимого, длина-произведения, адрес-произведения Согласно команде DIVP упакованные десятичные данные, оп- ределяемые второй парой операндов, делятся на данные того же типа, определяемые первой парой операндов, а результат записывается в область памяти, определяемую третьей парой операндов. Результат выполнения этой команды так же воздей-
Команды для десятичных чисел и чисел с плавающей точкой 377 ствует на биты Z, N и V признака результата, как и в случае команды DIVL. Также возникает ошибка при равенстве нулю делителя, причем, как и в случае деления целых чисел, эту ошибку нельзя замаскировать. Выполнение команды DIVP со- провождается разрушением предыдущего содержимого регистров R0—R5. Отметим, что эта команда не позволяет получить зна- чение остатка результата деления. Команда MULP обеспечивает перемножение упакованных де- сятичных данных. Подобно команде DIVP она уничтожает пре- дыдущее содержимое регистров R0—R5 и устанавливает соот- ветствующие значения битов N, Z и V признака результата. Для умножения и деления упакованных десятичных чисел на 10 в некоторой степени можно использовать команду ASHP (АРИФМЕТИЧЕСКИЙ СДВИГ И ОКРУГЛЕНИЕ УПАКОВАН- НОГО ДЕСЯТИЧНОГО ЧИСЛА), позволяющую сдвигать упа- кованные десятичные числа влево и вправо. Обобщенная форма этой команды: ASHP счетчик, длина „операнда-источника, адрес „операнда-источника, слагаемое „округления, длина„операнда-приемника, адрес „операнда-приемника Операнд счетчик определяет как направление, так и величину сдвига, равную значению показателя степени (порядка) чис- ла 10, результат возведения которого в эту степень умножается (если показатель степени — число положительное) или делится (если показатель — число отрицательное) на число, определяе- мое операндом-источником. Сдвиг влево на 2 эквивалентен умножению на 100, сдвиг вправо на 3 — делению на 1000. Ну- левое значение сдвига не изменяет значения обрабатываемых данных. Операнд слагаемое_округления конкретизирует опера- цию округления, выполняемую при сдвиге влево (делении). Биты 0—3 значения этого операнда добавляются к двоичному коду самой старшей значащей из сдвигаемых цифр младших разрядов. Если результат сложения больше, чем 9, то к значе- нию сдвинутого числа добавляется 1, после чего оно помеща- ется по адресу, определяемому операндом-приемником. Так, если цифра, крайняя слева среди подвергнутых сдвигу, равна 7, а значение операнда слагаемое„округления равно 5, то их сум- ма равна 12. Эта сумма больше, чем 9, а поэтому выполняется так называемый десятичный перенос единицы с ее последующим добавлением к результату сдвига. Обычно в качестве порога округления десятичных цифр выбирают цифру 5. Это и определяет типовое значение операнда
378 Глава 12 слагаемое-округления. Если сдвиг отрицательный, то и значе- ние указанного операнда считают отрицательным. Нулевое зна- чение операнда слагаемое-округления приводит к отбрасы- ванию (отсечению) цифр, оказавшихся за полем представления десятичного числа. Для размещения числового значения опе- ранда слагаемое-округления отведено поле размером байт, для числовых значений операндов длина-операнда-источника и дли- на-операнда-приемника — поля размером слово. Единственным достоинством команды ASHP в сравнении с командами MULP и DIVP является значительно более высо- кая скорость ее выполнения. Команды СМРРЗ и СМРР4 используются для сравнения упакованных десятичных данных: первая служит для сравнения двух строк упакованных десятичных цифр равных длин, вто- рая— неравных. Эти команды имеют следующие обобщенные формы: СМРРЗ длина, адрес_1, адрес_2 СМРР4 длина_1, адрес_1, длина-2, адрес_2 Результат выполнения этих команд оказывает воздействие только на значения битов признака результата. 12.3.3. Команды преобразования десятичных данных Рассмотрим команды преобразования десятичных данных из одной формы представления в другую, а также команды преоб- разования упакованных десятичных данных в целые числа раз- мером длинное слово и обратного преобразования. Для взаимного преобразования целых чисел размером длин- ное слово с одной стороны и упакованных десятичных чисел с другой используются команды CVTLP и CVTPL, имеющие следующую обобщенную форму: CVTLP длинное-слово, длина-упакованных-данных, адрес-упакованных-данных CVTPL длина-упакованных-данных, адрес-упакованных-данных, длинное_слово Команда CVTLP преобразует заданное длинное слово (целое число) в упакованное десятичное число и размещает результат в поле, размер и адрес которого определяются вторым и тре- тьим операндами команды. После выполнения команды содер- жимое регистров R0—R2 равно нулю, а в R3 размещается адрес байта памяти, содержащего самую старшую значащую упако- ванных десятичных данных. Результат выполнения команды воздействует на значения битов N, Z и V признака результата.
Команды для десятичных чисел и чисел с плавающей точкой 379 Биту V присваивается значение 1, когда мало поле, предостав- ляемое для размещения результата упаковки целого числа раз- мером длинное слово. Поскольку в данном слове может содер- жаться до 10 десятичных цифр, следует в качестве значения операнда длина„упакованных„данны.х использовать число 10. Это гарантирует от возникновения переполнения. Команда CVTPL преобразует упакованное десятичное число в целое число размером длинное слово и помещает результат в поле, адресуемое третьим операндом. После выполнения команды содержимое регистров RO, R2 и R3 равно нулю, а в ре- гистре R1 находится адрес байта, содержащего самую старшую цифру упакованного десятичного числа. Однако любой из ре- гистров R0—R3 может использоваться командой CVTPL для размещения результата. Как и CVTLP, данная команда воз- действует на значения битов N, Z и V признака результата. Биту V присваивается значение 1, когда значение упакованного десятичного числа выходит за пределы диапазона значений це- лых чисел, размещаемых в длинном слове, т. е. значений от —2 147483 648 до 2 147 483 647. Команды CVTPS и CVTSP выполняют преобразования строк упакованных десятичных цифр в числовые строки с раздельным ведущим знаком и обратно. Отметим, что буква S указывает на манипуляции с числовыми строками с раздельным ведущим знаком. Эти команды имеют следующие обобщенные формы; CVTPS длина_упакованной_строки, адрес_упакованной_строки, длина _строки„с-ведущим „знаком, адрес _строки„с _ведущим_знаком CVTSP длина„строки_с _ведущим„знаком, адрес _ строки„ с„ведущим„знаком, длина„упакованной„строки, адрес„упакованной„строки Команда CVTPS преобразует строку упакованных десятич- ных цифр, задаваемую первыми двумя операндами, в числовую строку с раздельным знаком и помещает результат в поле, за- даваемое двумя последними операндами. Следует помнить, что длины обеих строк определяются количеством цифр в строке без учета знака. Результат выполнения команды воздействует на биты N, Z и V признака результата. После выполнения команды содержимое регистров R0 и R2 равно нулю, в реги- стре R1 находится адрес байта строки упакованных десятичных цифр, содержащего самую старшую значащую цифру, а в ре- гистре R3 — адрес байта знака числовой строки с раздельным ведущим знаком. Сам знак («+» или «—>) представлен в коде ASCII. Подобно другим командам преобразования числовых
380 Глава 12 строк или выполнения арифметических операций над ними команда CVTPS не формирует нулевых значений со знаком «минус». В таких случаях знак изменяется на «плюс». Команда CVTSP преобразует числовую строку с раздельным ведущим знаком, задаваемую первыми двумя операндами, в строку упакованных десятичных цифр и помещает ее в поле, задаваемое двумя последними операндами. Эта команда выпол- няет проверку и способна обнаруживать в операндах ошибки нескольких типов. Использование зарезервированного (недо- пустимого к изменению) значения операнда регистрируется в тех случаях, когда либо длина строки, задаваемой операндом, выходит за пределы диапазона 0—31, либо какой-нибудь байт числовой строки с раздельным ведущим знаком содержит код, отсутствующий в перечне кодов ASCII для цифр от 0 до 9, либо код в байте знака не является кодом ASCII пробела, знака «+» или знака «—». Результат выполнения данной команды воздействует на биты N, Z, и V признака результата. После выполнения команды содержимое регистров R0 и R2 равно нулю, в регистре R1 находится адрес байта знака числовой строки с раздельным ведущим знаком, а в регистре R3—адрес байта, содержащего самую старшую значащую цифру строки упакованных десятичных цифр. Последние две команды десятичной арифметики преобра- зуют числовые строки с ведомым знаком в строки упакованных десятичных цифр и обратно. Эти команды имеют следующий обобщенный формат: CVTPT длина_упакованной_строки, адрес-упакованной_строки, таблица, д лина _ст р о ки_ с-ведомым-Знаком, адрес _ст роки _с_ведомым-знаком CVTTP длина _ст роки _с-ведомым-Знаком, адрес _строки_с_ведомым_знаком, таблица, длина_упакованной_строки, адрес-упакованной_строги В этих командах операнд таблица обеспечивает перевод (транс- ляцию) содержимого последнего байта числовой строки с ве- домым знаком. Это содержимое — результат совмещения по- следней цифры строки и знака. Длина указанной таблицы, име- нуемой таблицей переходов, равна 256 байт. Ее функции по- добны функциям аналогичной таблицы, используемой коман- дами SPANC и SCANC. Подлежащий переводу байт выполняет роль индекса таблицы; содержимое индексируемого поля таб- лицы и является искомым результатом процедуры «перевода» заданного байта. Применительно к команде CVTPT в полях таблицы должны находиться все возможные значения байта с наибольшим адресом среди всех байтов строки упакованных
Команды для десятичных чисел и чисел с плавающей точкой 381 десятичных цифр. Такой байт всегда содержит в одном полу- байте код знака, в другом — код десятичной цифры. Поскольку в полубайте знака возможны коды всех шестнадцатеричных цифр, больших 9, таблица должна содержать 60 полей, запол- ненных значимой информацией. Эти поля имеют шестнадцате- ричные адреса АО, ..., А9, ВО, ..., В9, ..., F0, .. , F9. Со- держимое каждого поля должно представлять собой результат упомянутого выше перевода в форме байта, представляющего самую младшую значащую цифру и знак числовой строки с ве- домым знаком. Например если для знака используется зонный формат 1, то поле с адресом А5 должно содержать шестна- дцатеричное число 35, что в свою очередь требует такого же содержимого полей с адресами С5, Е5 и F5 (поскольку все пе- речисленные адреса являются другими допустимыми формами представления 4-5 в строке упакованных десятичных цифр). Отметим, что таблица используется исключительно для пере- вода одного байта строки упакованных десятичных цифр, а именно такого, который содержит код знака. Коды других цифр указанной строки переводятся в десятичные цифры согласно коду ASCII. Результат выполнения команды CVTPT воздействует на биты N и Z признака результата в соответствии с тем, каковы знак и значение строки упакованных десятичных цифр. Биту V присваивается значение 1, если поле, предоставляемое для чис- ловой строки с ведомым знаком, оказывается недостаточным для размещения результата преобразования строки упакован- ных десятичных цифр. После выполнения команды содержимое регистров R0 и R2 равно нулю, в регистре R1 находится адрес байта, содержащего самую старшую значащую цифру строки упакованных десятичных цифр, а в регистре R3 — адрес самой старшей значащей цифры числовой строки с ведомым знаком. Команда CVTTP использует таблицу переходов для преоб- разования байта числовой строки с ведомым знаком, содержа- щего самую младшую значащую цифру и знак. Этот байт играет роль индекса (целого числа без знака) адресуемого поля таблицы. Содержимое этого поля размером байт является бай- том с самым большим адресом среди всех байтов строки упа- кованных десятичных цифр. Например, поля таблицы с шест- надцатеричными индексами (адресами) 4В и 72 должны иметь одинаковое содержимое D2, являющееся кодом числа —2 в строке упакованных десятичных цифр. При этом 4В — это шест- надцатеричный код числа —2 в так называемом зонном фор- мате 2 (используемом для кодирования знака и примыкающей к нему самой младшей значащей цифры числовой строки с ве- домым знаком), а 72—шестнадцатеричный код того же числа —2 в зонном формате 1, применяемом для тех же целей.
Таблица 12.1. Команды преобразования десятичных чисел Целое число размером байт Целое число размером слово Целое число размером длинное слово Целое число размером байт CVTBW CVTBL Целое число размером сло- во CVTWB CVTWL Целое число размером длинное слово CVTLB CVTLW Число с плавающей точкой одинарной точности CVTFB CVTFW CVTFL CVTRFL Число с плавающей точкой двойной точности CVTDB CVTDW CVTDL CVTRDL Числовая строка с раз- дельным ведущим знаком Числовая строка с ведо- мым знаком Упакованное десятичное число CVTPL
Число с плавающей точкой одинарной точности Число с плавающей точкой двойной точности Числовая строка с раздель- ным ведущим знаком Числовая строка с ведомым знаком Упакован- ное десятичное число CVTBF CVTBD CVTWF CVTWD CVTLF CVTLD CVTLP CVTFD CVTDF CVTSP CVTTP CVTPS CVTPT 382 Глава 12
Команды для десятичных чисел и чисел с плавающей точкой 383 Команда CVTTP выполняет проверку и способна обнару- живать в операндах ошибки нескольких типов: использование недопустимых по значению операндов, размеры которых выхо- дят за диапазон 0—31; наличие в любой (кроме самой младшей по порядку) позиции числовой строки с ведомым знаком байта, представляющего десятичную цифру, которая не имеет эквива- лента в коде ASCII; попытка выполнения перевода с помощью таблицы переходов наименьшей значащей цифры, используя несуществующий код для упакованной десятичной цифры или знака, представленного полубайтом. После выполнения этой команды содержимое регистров R0 и R2 равно нулю, в реги- стре R1 находится адрес самой старшей значащей цифры чис- ловой строки с ведомым знаком, а в регистре R3 — адрес байта, содержащего самую старшую значащую цифру строки упако- ванных десятичных цифр. Все рассмотренные команды преобразования данных, исполь- зуемые в системе VAX, приведены в табл. 12.1. Приводимый ниже пример иллюстрирует применение неко- торых команд десятичной арифметики. Д Пример 12.4 • Постановка задачи Исходные данные: строка, содержащая не более 20 симво- лов, представляющих собой пробелы, среди которых имеется одно десятичное число со знаком; количество разрядов числа меньше четырех. Искомый результат: возведенное в третью степень исходное десятичное число размером длинное слово. Отметим, что данное число, подлежащее вводу, представлено в форме числовой строки с раздельным ведущим знаком. Хотя решение этой задачи не должно вызывать особых затруднений, рассмотрим описание его алгоритма на псевдокоде, а затем тек- ста программы на языке ассемблера. • Алгоритм решения задачи на псевдокоде Ввести исходную строку символов Найти начало числа Найти конец числа Преобразовать число в упакованное десятичное Возвести число в степень 3 Преобразовать результат в целое число размером длинное слово Вывести результат Конец программы
384 Глава 12 • Программа на языке ассемблера . ПРЕОБРАЗОВАНИЕ ФОРМАТА ПРЕДСТАВЛЕНИЯ ДЕСЯТИЧНОГО ЧИСЛА И ВЫПОЛНЕНИЕ • АРИФМЕТИЧЕСКИХ ОПЕРАЦИЙ ; ИСХОДНЫЕ ДАННЫЕ: СТРОКА СИМВОЛОВ; КОЛИЧЕСТВО СИМВОЛОВ МЕНЬШЕ 20; ВСЕ СИМВОЛЫ - ПРОБЕЛЫ ЗА ИСКЛЮЧЕНИЕМ ТЕХ, КОТОРЫЕ ; ОБРАЗУЮТ ДЕСЯТИЧНОЕ ЧИСЛО ; СО ЗНАКОМ; ВЕЛИЧИНА ЧИСЛА ; СОДЕРЖИТ МЕНЕЕ ЧЕТЫРЕХ РАЗРЯДОВ ;РЕЗУЛЬТАТ: ВОЗВЕДЕННОЕ В СТЕПЕНЬ 3 ИСХОДНОЕ ;ДЕСЯТИЧНОЕ ЧИСЛО, ПРЕДСТАВЛЕННОЕ КАК ДЛИННОЕ СЛОВО .PSECT EXAMPLE, LONG РЕЗЕРВИРОВАНИЕ ПАМЯТИ ДЛЯ IN_ STRING: .BYTE ~A/ /[20] ; ИСХОДНОЙ СТРОКИ СИМВОЛОВ IN_S: .BLKB 5 ; ;ИСХОДНОЙ СТРОКИ С РАЗДЕЛЬНЫМ ВЕДУЩИМ ЗНАКОМ IN_P: .BLKB 2 ; ИСХОДНОЙ СТРОКИ КАК УПАКОВАННОГО ДЕСЯТИЧНОГО ЧИСЛА SQUARE: .BLKB 4 ; КВАДРАТА ИСХОДНОГО ЧИСЛА CUBE: .BLKB 5 * КУБА ИСХОДНОГО ЧИСЛА OUT: .BLKL 1 РЕЗУЛЬТАТА LENGTH: .ENTRY INIT_IO READ-A .BLKL 1 ; EX_12_4,0 IN_STRING ДЛИНЫ ИСХОДНОЙ СТРОКИ СИМВОЛОВ ОПРЕДЕЛЕНИЕ ПОЗИЦИИ НАЧАЛА И КОНЦА ЧИСЛА SKPC #~А/ /,#20, IN_STRING MOVL RO, R2 MOVL RL R3 LOCC #~A/ /,RO,(R1) SUBL3 RO, R2, LENGTH DECL LENGTH ПРЕОБРАЗОВАНИЕ ЧИСЛОВОЙ СТРОКИ В УПАКОВАННЫЕ ДЕСЯТИЧНЫЕ ДАННЫЕ ’ CVTSP LENGTH, (R3), #3, IN_P ; ВОЗВЕДЕНИЕ ЧИСЛА В ТРЕТЬЮ СТЕПЕНЬ
Команды для десятичных чисел и чисел с плавающей точкой 385 MULP #3, IN.P, #3, IN_P, #6, SQUARE MULP #3, IN_P, #6, SQUARE, #9, CUBE ; ПРЕОБРАЗОВАНИЕ РЕЗУЛЬТАТА В ЦЕЛОЕ ЧИСЛО ; РАЗМЕРОМ ДЛИННОЕ СЛОВО CVTPL #9, CUBE, OUT PRINT.L '•'ИСХОДНОЕ ЧИСЛО В СТЕПЕНИ 3 = ',OUT $EXIT_S .END ЕХ.12.4 Выводы 1. Представление чисел в форме с плавающей точой ис- пользуется в прикладных программах для выполнения научно- технических расчетов. Эта форма соответствует математической записи числа в виде мантиссы и порядка. Числа с плавающей точкой одинарной точности могут содержать до семи значащих десятичных цифр, диапазон значений этих чисел от 0.29Е—38 до 1.7Е38. 2. Директива .FLOAT предназначена для выделения обла- стей памяти числам с плавающей точкой одинарной точности и присвоения содержимому этих областей определенных значе- ний, директива .BLKF — для выделения подобных областей с присвоением их содержимому нулевых значений. 3. Числа с плавающей точкой одинарной точности можно пересылать, используя команды MOVF и MNEGF, проверять посредством команды TSTF, сравнивать с помощью команды CMPF. Команды MOVAF и PUSHAF применяются для пере- сылки адресов местоположения таких чисел, команда PUSHL — для загрузки чисел в стек, команда CLRF — для очистки обла- стей памяти, используемых числами с плавающей точкой оди- нарной точности, команды ADDF2 и ADDF3 — для сложения подобных чисел, команды SUBF2 и SUBF3 — для их вычитания, DIVF2 и DIVF3 — для деления, a MULF2 и MULF3 — для умно- жения. Результаты выполнения этих команд округляются. 4. Команда ACBF предназначена для организации циклов, управляемых счетчиком и использующих в качестве параметра цикла числа с плавающей точкой одинарной точности. 5. Числа с плавающей точкой одинарной точности можно преобразовывать в целые числа размером байт, слово и длинное слово посредством команд CVTFB, CVTFW и CVTFL соответ- ветственно. Команда CVTRFL позволяет выполнить округление числа с плавающей точкой перед его преобразованием в целое число размером длинное слово. Целые числа размером байт, слово и длинное слово можно преобразовывать в числа с пла- 13 Зак. 483
386 Глава 12 вающей точкой одинарной точности, используя команды CVTBF, CVTWF и CVTLF соответственно. 6. Система VAX оперирует числами с плавающей точкой двой- ной точности, которые могут содержать до 16 десятичных цифр такого же диапазона допустимых значений, как и числа с пла- вающей точкой одинарной точности. 7. Система VAX допускает использование десятичных чис- ловых данных в трех формах представления: в виде числовой строки с раздельным ведущим знаком, с ведомым знаком и строки упакованных десятичных цифр. Первые две формы пред- ставляют каждую цифру в неупакованном виде, используя байт для размещения кода одной цифры, последняя форма — в упа- кованном, размещая по две цифры в одном байте. 8. Единственными командами, оперирующими неупакован- ными десятичными числовыми данными, являются команды пре- образования этих данных в упакованные десятичные данные и обратно, а именно: CVTPS, CVTSP, CVTPT и CVTTP. 9. Упакованные десятичные данные можно формировать, ис- пользуя директиву .PACKED, пересылать с помощью команды MOVP, складывать посредством команд ADDP4 и ADDP6, вы- читать, применяя команды SUBP4 и SUBP6, делить и умно- жать с помощью команд DIVP и MULP соответственно, а также сравнивать, используя команды СМРРЗ и СМРР4. Эти числа можно сдвигать влево или вправо посредством команды ASHP. Упакованные десятичные числа можно преобразовывать в це- лые числа размером длинное слово и выполнять обратные пре- образования с помощью команд CVTLP и CVTPL. Новые команды ACBD СМРР4 CVTLP DIVF3 MULP ACBF CVTBD CVTPL DIVP POLYD ADDD2 CVTBF CVTPS MNEGD POLYF ADDD3 CVTDB CVTPT MNEGF PUSHAD ADDF2 CVTDF CVTRDL MOVAD PUSHAF ADDF3 CVTDL CVTRFL MOVAF SUBD2 ADDP4 CVTDW CVTSP MOVD SUBD3 ADDP6 CVTFB CVTTP MOVF SUBF2 ASHP CVTFD CVTWD MOVP SUBF3 CLRD CVTFL CVTWF MULD2 SUBP4 CLRF CVTFW DIVD2 MULD3 SUBP6 CMPD CVTLD DIVD3 MULF2 TSTD CMPF CVTLF DIVF2 MULF3 TSTF СМРРЗ
Команды для десятичных чисел и чисел с плавающей точкой 387 Новые директивы .BLKD .BLKF .□.FLOATING .DOUBLE .ENABLE TRUNCATION F_ FL GATING .FLOAT .PACKED Новые термины Запись порядка с избытком 128 Зонный формат 1 (для знака) Зонный формат 2 (для знака) Числовая строка с ведомым знаком Числовая строка с раздельным ведущим знаком Вопросы и упражнения 1. Сколько значащих десятичных цифр может иметь резуль- тат выполнения каждой арифметической операции над числами с плавающей точкой одинарной точности? 2. Сколько значащих десятичных цифр может иметь резуль- тат выполнения каждой арифметической операции над числами с плавающей точкой двойной точности? 3. Что происходит при формировании посредством директи- вы .FLOAT константы С с избыточным количеством десятичных цифр: округление числа или усечение этих цифр? (Предполага- ется выполнение округления или усечения по умолчанию). 4. Объясните, каким образом удается разместить 24 бит мантиссы в поле из 23 двоичных разрядов, которое предостав- ляется для нее форматом числа с плавающей точкой одинарной точности. 5. Объясните, как число, равное нулю, представляется в фор- мате чисел с плавающей точкой одинарной точности. 6. Укажите двоичные коды представления в формате с пла- вающей точкой одинарной точности следующих десятичных чи- сел: а) 67; б) —42; в) 161; г) 17. 7. Укажите десятичные значения следующих шестнадцате- ричных эквивалентов чисел с плавающей точкой одинарной точ- ности: а) 00004240; б) 0000С2А8; в) 00004148; г) 0000С190. 8. Какие выполняются действия, если первый операнд команды CVTFB равен 285? 9. Почему в примере 12.2 для вычисления факториала ис- пользуются числа с плавающей точкой, хотя известно, что фак- ториал— принимающая целочисленные значения функция це- лого числа? 13*
388 Глава 12 10. Можно ли утверждать, что любая модификация вычис- лительной системы VAX располагает для представления чисел с плавающей точкой форматами G и Н? II. В каких языках программирования чаще всего использу- ются команды десятичной арифметики? 12. Представьте число —4276 в виде числовой строки с раз- дельным ведущим знаком. 13. Представьте число —4276 в виде числовой строки с ве- домым знаком. 14. Представьте число —4276 в виде строки упакованных десятичных цифр. 15. Как с помощью команды ASHP можно выполнять опе- рации деления с отбрасыванием дробных частей результата? 16. Сформируйте 256-байтовую таблицу переходов для коман- ды CVTTP. Напишите и выполните отладку программ на языке ассем- блера для перечисляемых ниже задач. 17. Исходные данные: целое положительное число размером длинное слово. Искомый результат: целочисленное значение результата из- влечения квадратного корня из исходного числа путем исполь- зования следующей итерационной формулы: NEXT-GUESS := OLD_GUESS+ (((INPUT/OLD_GUESS)— — OLD_GUESS)/2), где начальное значение переменной OLD-GUESS равно (исход- ное число + 1)/2. Примечание. Для всех вычислений в программе следует при- менять команды, выполняющие операции над числами с пла- вающей точкой. Итерационный процесс вычислений необходимо прекратить, когда NEXT-GUESS OLD-GUESS (Эти итера- ционные вычисления известны под названием метода Ньюто- на — Рафсона.) 18. Исходные данные: число с плавающей точкой. Искомый результат: значение антилогарифмической функции исходного числа, вычисляемой как сумма членов ряда Тейлора ех : = 1 + х + х2/2! + х3/3! + ... Примечание. Решение данной задачи оформить в виде под- программы, единственным параметром которой является аргу- мент вычисляемой антилогарифмической функции. Суммирова- ние членов указанного ряда прекратить после добавления оче- редного слагаемого, значение которого меньше, чем 0,00001. 19. Исходные данные: последовательность целых чисел, со- держащих от 5 до 9 цифр,
Команды для десятичных чисел и чисел с плавающей точкой 389 Искомый результат: сумма квадратов исходных чисел. Примечание. Перед возведением во вторую степень каждое исходное число должно быть представлено в виде упакованного десятичного числа. Результат подлежит выводу в форме число- вой строки с раздельным ведущим знаком посредством коман- ды PRINT.A. 20. Исходные данные: последовательность целых чисел, со- держащих от 20 до 30 десятичных цифр, которая поступает с терминала таким образом, что числа начинаются с первой позиции каждой входной строки. Искомый результат: значение числа, играющего роль ме- дианы исходной последовательности. Примечание. Все операции ввода и вывода необходимо вы- полнять, используя команды READ.А и PRINT.A. Для выпол- нения операций сравнения и пересылки числа должны быть пред- ставлены как упакованные десятичные данные. Под медианой следует понимать средний элемент сортируемой последователь- ности. Если количество элементов последовательности — четное число, то медиану следует определять как среднее арифметиче- ское двух средних элементов. 21. Исходные данные: последовательность положительных чисел с плавающей точкой, которая заканчивается отрицатель- ным числом. Искомый результат: количество исходных чисел, значения которых больше значения среднего арифметического всех ис- ходных чисел.
Глава 13 Операции над битами и логические операции Во многих ситуациях бывает удобно или даже необходимо оперировать отдельными битами, входящими в строку, или выделять и анализировать отдельные части строк (подстроки) битов. Рассмотрим, например, процедуру, обратную ассемблированию, которую осуществляет отладчик для команд STEP и EXAMINE/INSTRUCTION. Для реализации этих команд требуются программные средства построения команды языка ассемблера из машинных команд VAX, которые являются в ко- нечном счете просто строками битов. Логические операции применяются для самых разнообраз- ных целей, в том числе в задачах алгебры логики и операциях над множествами, представляемыми строками битов. В предыдущих главах операции над битами и логические операции не рассматривались, однако изучение машины и ма- шинно-ориентированного языка нельзя считать завершенным без ознакомления с этими возможностями. 13.1. Данные в виде строки битов Среди данных различных типов, используемых при программи- ровании на языке ассемблера системы VAX, до сих пор не рас- сматривались только данные, представляемые в виде строк би- тов. Данные этого типа занимают особое положение по отноше- нию к данным других типов, таких, например, как целые числа размером слово или длинное слово. Строку битов нельзя индекс сировать, для строки битов требуемой длины нельзя зарезерви- ровать память с помощью директив языка ассемблера. Более точно строки битов в системе VAX могут быть определены как подстроки данных других типов. Для полного описания строки битов в машинной команде требуются три операнда: базовый адрес, смещение бита и дли- на. Операнд базовый_адрес представляет собой адрес байта, ко- торый может быть определен с помощью любого режима адре- сации машины VAX. Значение операнда длина задается целым числом размером байт, а значение операнда смещение — целым числом со знаком размером длинное слово; к этим данным мож^ но обращаться, используя любой допустимый режим адресации.
Операции над битами и логические операции Местоположение строки определяется значением указанного смещения, являющегося «расстоянием» между битом 0 байта, адресуемого операндом базовый-адрес и битом 0 байта, являю- щегося началом строки. Поскольку смещение имеет знак, стро- ка может располагаться с любой стороны от базового адреса. Смещение задается в виде 32-разрядной двоичной последова- тельности, которая интерпретируется как 29-разрядное двоичное число со знаком, определяющее смещение байта, и трехразряд- ное двоичное число, указывающее смещение бита внутри этого байта. Размер строки битов ограничивается диапазоном от О до 32 двоичных разрядов. Если значение операнда длина выхо- дит за пределы этого диапазона, то в большинстве случаев ре- гистрируется ошибка «недопустимый операнд». Длина Смещение Старшие адреса Строка битов Младшие адреса Базовый адрес Рис. 13.1. Машинное представление строки битов. Этот несколько странный способ адресации «база плюс сме- щение» используется потому, что адреса битов в системе VAX не умещаются в 32-разрядное длинное слово. Все 32 разряда нужны для адресации байта в виртуальном адресном простран- стве. Для указания в этом байте начала строки бита требуются еще 3 разряда, и, следовательно, для полного адреса этого бита необходимо 35 разрядов. Эта проблема решается применением двухкомпонентного адреса (т. е. состоящего из двух частей). Поскольку часто приходится оперировать с полями битов внутри регистров, базовый адрес может относиться к регистру в той же мере, как и к области памяти при условии, что вели- чина смещения не выходит за пределы диапазона значений О—31. Отметим, что только в таких ситуациях архитектура VAX допускает обращение к регистру с помощью операнда, значе- нием которого является адрес. Обобщенный формат строки битов показан на рис. 13.1. 13.2. Операции над строками битов Если данные занимают всего один двоичный разряд, необходи- мые операции под ними обычно очень просты. Такими данны- ми, например, являются биты признака результата (биты-инди-
392 Глава 13 каторы), а типовой операцией над ними — операция проверки значения бита. В системе имеется несколько команд условной передачи управления (условного перехода), которые оперируют однобитовыми данными. Например, внутри процедуры можно определить, каким образом процедура была вызвана (с по- мощью CALLS или CALLG), если воспользоваться командой условной передачи управления, анализирующей значение бита S в информационном длинном слове блока вызова. Битовая адресация обычно применяется в двух типах команд условного перехода. К первому типу относятся команды, кото- рые выполняют только передачу управления по условию. Для символического обозначения кода их операций используется ВВх (BRANCH BIT —ПЕРЕХОД ПО ЗНАЧЕНИЮ БИТА). Команды второго типа (ВВхх) передают управление после про- верки условия и оказывают воздействие на значение проверяе- мого бита. Анализируемая этими командами строка битов со- стоит из единственного бита, поэтому спецификация длины строки не требуется. Обобщенный формат команд типа ВВх имеет следующий вид: ВВх смещение, база, адрес В качестве символического обозначения кода операции ис- пользуются ВВС и BBS для передачи управления, если прове- ряемый бит равен 0 или 1 соответственно. Первый операнд команды указывает смещение в виде целого числа размером длинное слово относительно базового адреса, задаваемого вто- рым операндом. Последний операнд определяет адрес перехода. Как и в других командах условного перехода, этот адрес — це- лое число размером байт. Такой размер поля представления адреса ограничивает максимальное «расстояние» между адре- сами команды и перехода 127 байтами. Рассмотрим пример машинного кода, соответствующего команде типа ВВх: ВВС R7 » (R6) t OUT, .3310 1421 66|57|еГ] Эта команда анализирует значение бита, адрес которого определяется смещением, содержащимся в регистре R7, отно- сительно байта, адрес которого указан в регистре R6. Если значение бита равно 0, для получения адреса символического имени OUT к содержимому счетчика команд добавляется 42. (шестнадцатеричное число),
Операции над битами и логические операции 393 В следующем примере команда ВВС используется для пере- дачи управления на метку CALLG, если значение бита S в бло- ке вызова указывает на вызов текущей процедуры с помощью CALLG. Напомним, что бит размещается в разряде 29 второго длинного слова блока вызова, адресуемого указателем FP. ВВС #29, 4(FP), CALLG Четыре команды типа ВВхх (ПРОВЕРИТЬ И ИЗМЕНИТЬ) сначала анализируют значение бита, а затем присваивают ему значение 0 или 1. Обобщенный формат этих команд такой же, как и у команд типа ВВх. В качестве кодов операций могут использоваться следующие символические имена: ВВСС (ПЕРЕ- ХОД, ЕСЛИ БИТ РАВЕН О, И ПРИСВОЕНИЕ БИТУ ЗНАЧЕ- НИЯ 0), BBSC (ПЕРЕХОД, ЕСЛИ БИТ РАВЕН 1 И ПРИ- СВОЕНИЕ БИТУ ЗНАЧЕНИЯ 0), BBSS (ПЕРЕХОД, ЕСЛИ БИТ РАВЕН 1 И ПРИСВОЕНИЕ БИТУ ЗНАЧЕНИЯ 1) и BBCS (ПЕРЕХОД, ЕСЛИ БИТ РАВЕН 0 И ПРИСВОЕНИЕ БИТУ ЗНАЧЕНИЯ 1). Может возникнуть вопрос, для чего проверять значение бита и зачем в некоторых случаях (ВВСС, BBSS) присваивать ему то же самое значение. Ответ прост: хотя передача управления зависит от проверяемого условия, модификация значения бита — операция, выполняемая при всех условиях. Например, команда BBSS присваивает значение 1 ад- ресуемому биту независимо от его значения перед выполнением команды. Обобщенный формат команд типа ВВхх имеет следующий вид: ВВхх смещение, база, адрес Первые два операнда определяют адрес проверяемого бита, а третий операнд—адрес перехода. В частном случае проверяемый бит может быть младшим битом байта памяти или регистра. В набор команд системы VAX включены две предназначенные для таких ситуаций команды: BLBC (ПЕРЕХОД, ЕСЛИ МЛАДШИЙ БИТ РАВЕН 0) и BLBS (ПЕРЕХОД, ЕСЛИ МЛАДШИЙ БИТ РАВЕН 1). Обоб- щенный формат этих команд имеет следующий вид: BLBx исходное-поле, адрес Значение операнда исходное_поле определяется как целое число размером длинное слово и используется для адресации посредством любого допустимого режима. Как и в других командах условного перехода, операнд адрес задается как сме- щение размером байт, т. е. в адресном пространстве может от- стоять от данной команды на расстояние не более 127 байт,
394 Глава 13 Если каждый бит в строке битов представляет некоторое независимое значение, может потребоваться найти первый бит строки, равный 1 или 0. Предположим, например, что единичные значения битов интерпретируются как признаки использования соответствующих областей в качестве элементов некоторого мас- сива. Тогда для обнаружения свободной области из тех, кото- рые принадлежат массиву, в строке битов достаточно найти один, равный нулю. В системе VAX имеются две команды поиска битов: FFS(FIND FIRST BIT SET-ПОИСК ПЕРВОГО БИТА, РАВ- НОГО 1), и FFC(FIND FIRST BIT CLEAR - ПОИСК ПЕРВО- ГО БИТА, РАВНОГО 0). Обобщенный формат этих команд имеет следующий вид: FFx смещение, длина, база, результат Операнды смещение, длина и база определяют поле (адрес л длину), занимаемое строкой битов. Значение операнда сме- щение должно быть целым числом со знаком размером длинное слово, операнд база является адресом, а операнд длина должен быть определен как целое число размером байт, значение ко- торого не выходит за пределы диапазона 0—32. Строка битов извлекается из поля с указанным адресом и затем просматри- вается слева направо до обнаружения первого бита, имеющего заданное значение (единицы при использовании команды FFS и нуля при использовании команды FFC). Если указанное зна- чение найдено, биту Z признака результата присваивается зна- чение 0, и смещение найденного бита относительно базы поме- щается в поле размером длинное слово, адресуемое операндом результат. Если бит с указанным значением не найден, биту Z присваивается значение 1 и в поле, адресуемое операндом ре- зультат, записывается значение смещения первого следующего за анализируемой строкой бита относительно базы. Отметим, что, если значение операнда длина задано равным нулю, биту Z присваивается значение 1, а содержимому поля, адресуемому операндом результат, — значение первого операнда (смещение первого бита в строке). Команды FFx можно использовать для просмотра длинных строк битов. Предположим, например, что строка битов исполь- зуется для отображения состояния массива из 512 элементов: каждый бит определяет текущее состояние соответствующего ему одного элемента. Поскольку начальное смещение, задавае- мое первым операндом команды FFx, может быть больше 31, если строка размещается в памяти, можно построить цикл, включив в него команду FFx с операндом длина, значение ко-
Операции над битами и логические операции' 395 торого равно 32. Если использовать одну и ту же область па- мяти для начального смещения и результата, то каждая коман- да FFx, завершившаяся неуспешно, увеличит начальное смеще- ние на 32 и таким образом обеспечит перемещение к началу следующего длинного слова данных. Пусть бит со значением 0 соответствует доступному (не ис- пользуемому в данный момент) элементу массива. Тогда с по- мощью фрагмента программы, приводимого в примере 13.1, можно найти первый свободный элемент путем просмотра стро- ки битов FLAGS. Смещение найденного бита записывается в поле POSITION, которое служит и для задания начального сме- щения. Этот фрагмент является хорошим примером цикла с проверкой условия его окончания после очередного выполнения операций тела цикла. В качестве модели цикла в комментариях фрагмента используется конструкция REPEAT (ПОВТОРЯТЬ) псевдокода, заимствованная из языка Паскаль. А Пример 13.1. Использование команды FFC FLAGS: .BLKL 16; СТРОКА БИТОВ FENCE: .BYTE 0; ПОЛЕ С НУЛЕВЫМ СОДЕРЖИМЫМ ; ДЛЯ ГАРАНТИИ ВЫХОДА ИЗ ЦИКЛА POSITION: .BLKL 1: ПОЛЕ НАЧАЛЬНОГО СМЕЩЕНИЯ И РЕЗУЛЬТАТА CLRL POSITION ; ПОВТОРЯТЬ LOOP: • ПРОСМОТР 32 БИТ ФЛАГОВ ’ FFC POSITION,’#32, FLAGS, POSITION BEQL LOOP • ПОКА БИТ Z HE СТАНЕТ РАВНЫМ НУЛЮ » Для того чтобы проверить, содержат ли 16 длинных слов поля FLAGS бит со значением 0, следует сравнить содержимое поля POSITION с 512. Если содержимое поля POSITION меньше, чем 512, то оно является смещением первого бита со значением 0. В противном случае поле FLAGS не содержит битов, равных 0. Еще одна группа команд используется для сравнения и пе- ремещения строк битов. Каждая из этих команд оперирует с
396 Глава 13 группой или полем битов. Символические имена кодов операций этих команд содержат букву V, указывающую, что поле битов имеет переменную (variable) длину. Команда INSV перемещает подстроку из младших разрядов длинного слова в поле битов. Обобщенный формат этой коман- ды имеет следующий вид: INSV исходное-поле, смещение, длина, база Первый операнд представляет собой длинное слово, младшие разряды которого подлежат перемещению. Остальные три опе- ранда определяют поле (адрес и длину), занимаемое строкой битов, и длину перемещаемой строки. Например, команда INSV #~XFOF , #4, #8, R3 перемещает первые 8 бит (т. е. в данном случае все) из поля первого операнда в регистр R3 со смещением 4 бита. Ниже при- водится машинное представление этой команды: 876 5432 1 О | 531081041 OOOOFOFF' 8F | FO | Выполнение команды INSV показано на рис. 13.2. Рис. 13.2. Выполнение команды INSV. Обратной по отношению к операции, выполняемой командой INSV, является операция перемещения содержимого поля би- тов в длинное слово. Для выполнения подобной операции си- стема VAX располагает двумя командами, называемыми коман- дами извлечения. Одна из них, именуемая EXTV, расширяет по- ле до 32 разрядов путем заполнения недостающих старших раз- рядов значением бита знака, а другая, по имени EXTZV, — ну* лем. Обобщенный формат этих команд имеет следующий вид; КОП смещение, длина, база, результат
Операции над битами и логические операции 397 Первые три операнда определяют поле (адрес и длину), зани- маемое строкой битов, а последний — длинное слово для разме- щения результата. Выполнение команд EXTV и EXTZV показа- но на рис. 13.3. EXTV #4|#12,R3,.R4 EXTZV #4t*iZiR3)R4 Рис. 13.3. Выполнение команд EXTV и EXTZV. При выполнении команд INSV, EXTV и EXTZV, а также команд типа FFx, операнд длина которых имеет значение боль- ше, чем 32, регистрируется ошибка «недопустимый операнд». В качестве примера использования команд извлечения рас- смотрим задачу преобразования целого числа размером длинное слово в шестнадцатеричное число в коде ASCII. Это преобразо- вание (как показано в примере 13.2) может быть выполнено пу- тем последовательного извлечения полубайтов длинного слова и использования их в качестве индексов для обращения к таб- лице кодов ASCII с целью отыскания шестнадцатеричных экви- валентов соответствующих кодов содержимого полубайта (деся- тичной цифры, знака «+», знака «—»).
398 Глава 13 Д Пример 13.2 • Постановка задачи Исходные данные-, целое число размером длинное слово. Искомый результат-, шестнадцатеричное представление исход- ного числа в коде ASCII. • Алгоритм решения задачи на псевдокоде Ввод целого числа размером длинное слово FOR DIGIT := 7 DOWNTO О DO Извлечь полубайт Преобразовать полубайт в шестнадцатеричную цифру в коде ASCII и поместить в поле OUTPUT END-FOR Вывод OUTPUT Конец программы • Программа на языке ассемблера ; ПРЕОБРАЗОВАНИЕ ЦЕЛОГО ЧИСЛА РАЗМЕРОМ ; ДЛИННОЕ СЛОВО В ШЕСТНАДЦАТЕРИЧНЫЙ ЭКВИВАЛЕНТ ; ЧИСЛА В КОДЕ ASCII ИСХОДНЫЕ ДАННЫЕ: ЦЕЛОЕ ЧИСЛО ; РАЗМЕРОМ ДЛИННОЕ СЛОВО ; ИСКОМЫЙ РЕЗУЛЬТАТ: ; ШЕСТНАДЦАТЕРИЧНОЕ ПРЕДСТАВЛЕНИЕ ; ИСХОДНОГО ЧИСЛА В КОДЕ ASCII .PSECT EXAMPLE, LONG HEX.ASCII: .ASCII /0123456789ABCDEF/; ТАБЛИЦА ПРЕОБРАЗОВА- ; НИЯ ПОЛУБАЙТОВ В КОД ASCII INPUT: .BLKL 1 ; ОБЛАСТЬ ПАМЯТИ ДЛЯ ИСХОДНОГО ЧИСЛА OUTPUT: .BLKB 8 ; ОБЛАСТЬ ПАМЯТИ ДЛЯ РЕЗУЛЬТАТА (СТРОКА СИМВОЛОВ) OUT-PTR: .BLKL 1 ; ОБЛАСТЬ ПАМЯТИ ДЛЯ УКАЗАТЕЛЯ ИСКОМОЙ СТРОКИ СИМВОЛОВ DIGIT: .BLKL 1 ; ОБЛАСТЬ ПАМЯТИ ДЛЯ СЧЕТЧИКА ЦИКЛА .ENTRY ЕХ_13_2, О INIT-IO PRINT-L '''ВВЕДИТЕ ЧИСЛО:' READ.L INPUT ; MOVAB OUTPUT, OUT-PTR I ; ДЛЯ DIGIT := 7 ДО О ВЫПОЛНЯТЬ В ЦИКЛЕ i MOVL #7, DIGIT
Операции над битами и логические операции 399 LOOP: ; ИЗВЛЕЧЕНИЕ ПОЛУБАЙТА I MULL3 #4, DIGIT, R0 EXTZV RO, #4, INPUT. Rl ; ПРЕОБРАЗОВАНИЕ ПОЛУБАЙТА В ШЕСТНАДЦАТЕРИЧНОЕ ; ПРЕДСТАВЛЕНИЕ ЕГО СОДЕРЖИМОГО В КОДЕ ASCII MOVB HEX-ASCII [Rl], «OUT-PTR INCL OUT-PTR SOBGEQ DIGIT, LOOP ; КОНЕЦ ЦИКЛА «ДЛЯ» PRINT-A-' РЕЗУЛЬТАТ/, # 8, OUTPUT $EXIT_S .END EX_ 13_2 Отметим, что если в качестве указателя поля OUTPUT ис- пользовать регистр, эту программу можно сделать более эффек- тивной как по объему занимаемой памяти, так и по скорости выполнения. Тогда для обращения к полю, задаваемому вторым операндом команды MOVB, можно применить косвенную адре- сацию с автоматическим увеличением адреса. Система VAX располагает двумя командами сравнения стро- ки или поля битов с содержимым длинного слова. Разумеется, эти команды нужны только в тех случаях, когда длина строки меньше 32 бит, потому что сравнение двух полных длинных слов может быть реализовано командой CMPL. Кроме того в опера- циях сравнения строк битов операндами чаще являются содер- жимое поля и литерал, а не содержимые двух полей. Строки- литералы наиболее эффективно могут быть представлены в виде содержимого длинного слова, поэтому именно такой тип данных выбирается для представления второго операнда. При выполнении команды CMPV содержимое поля перед сравнением расширяется до 32 бит путем заполнения разрядов значением бита знака (старшего бита строки). При выполнении команды CMPZV содержимое поля расширяется путем заполне- ния старших разрядов нулем. Обобщенный формат этих команд имеет следующий вид: КОП смещение, длина, база, обьект-сравнения Операнды смещение, длина и база определяют поле (адрес и длину), занимаемое строкой битов, а операнд объект-сравне- ния — длинное слово, с содержимым которого сравнивается строка.
400 Глава 13 Для примера рассмотрим следующие команды: CMPV #4, #4, FIRST, SECOND CMPZV #8, #4, FIRST, SECOND Первая из этих команд извлекает содержимое четырехбитового поля, расположенное внутри поля FIRST на «расстоянии» 4 бит (величина смещения) от его начала (второй полубайт поля FIRST), расширяет его до 32 разрядов путем заполнения стар- ших разрядов битами знака, и затем сравнивает с содержимым длинного слова SECOND. Вторая команда извлекает третий по- лубайт из поля FIRST, расширяет его до 32 бит путем заполне- ния старших разрядов нулями и сравнивает с содержимым длин- ного слова SECOND. Отметим, что действие этих команд эквивалентно действию команд извлечения, за которыми следует команда CMPL. 13.3. Команды сдвига Команды сдвига смещают содержимое регистров или областей памяти влево или вправо. Эти команды выполняют над строками битов действия, подобные тем, которые команда ASHP выпол- няет над строками упакованных десятичных цифр. В системе VAX команды сдвига играют меньшую роль, чем в более ран- них вычислительных машинах, не располагавших рассмотрен- ными выше командами обработки строк битов. В этих машинах команды сдвига широко использовались для выполнения опера- ций упаковки, распаковки и преобразования данных. Команда ASHx выполняет арифметический сдвиг, в резуль- тате которого знак числа сохраняет свое положение. Обобщен- ный формат команд ASHL и ASHQ имеет следующий вид: ASHx счетчик, исходные_данные, результат Первый операнд определяет одновременно количество битов, на которые производится сдвиг, и направление сдвига. Напри- мер, если содержимое счетчика равно 5, то производится сдвиг влево на 5 бит, а 5 правых двоичных разрядов поля заполняются нулями. При значении содержимого счетчика —3 производится сдвиг вправо на 3 бита, а левые 3 двоичных разряда заполняют- ся значением содержимого разряда знака, т. е. значение знака сохраняется. При нулевом значении содержимого счетчика сдвиг не выполняется. Счетчик занимает один байт. Операнды исходные „ данные и результат определяют соответ- ственно поле (адрес и длину), занимаемое подлежащими сдви- гу данными, и поле, в которое помещается результат сдвига. Отметим, что в результате выполнения команды сдвига содер- жимое исходного поля не меняется.
Операции над битами и логические операции 401 Команда ASHL используется для сдвига длинных слов, а команда ASHQ — двойных длинных слов. В результате выполне- ния этих команд биту-индикатору переполнения присваивается значение 1, если в процессе сдвига влево в разряд знака поме- щается (или через него «проходит») бит, значение которого отличается от знака исходного числа. Следующие примеры поясняют операции, выполняемые командами ASHx: 11111111 |1Ш1Ш 111110000111110000 ASHL. -«5» VALUE» VALUE цини |iiiiiiio|oooiiiio|oooooooo WASHL «-В» VALUE» VALUE iiiiiiu [шит | пито loooinio Содержимое поля VALUE Содержимое ПОЛЯ VALUE Содержимое поля VALUE Команды типа ASHx могут использоваться для реализации операций умножения и деления в тех случаях, когда от програм- мы требуется максимальное быстродействие. Рассмотрим сдвиг десятичного числа с помощью команды ASHP. Сдвиг вправо на п десятичных цифр эквивалентен деле- нию на 10л, сдвиг влево на п цифр — умножению на 10п. Анало- гично, сдвиг двоичного числа на п двоичных цифр (битов) соот- ветствует умножению или делению на 2Л. Например, сдвиг влево на 4 бита дает тот же результат, что и умножение на 24, т. е. на 16. Точно так же сдвиг вправо на три бита заменяет деление на 23. Однако команды сдвига могут за- менить команды умножения и деления только при умножении или делении на число, равное двум в соответствующей степени. Умножение или деление целесообразно заменять сдвигом только с целью повышения скорости выполнения этих арифмети- ческих операций. Сдвиг выполняется во много раз быстрее, чем умножение или деление. Отметим также, что команда ASHL со значением счетчика, равным или большим 32, эффективно очи- щает поле результата, делая его содержимое равным нулю. Од- нако команда CLRL является и более быстрым, и более нагляд- ным средством очистки адресуемого поля. В примере 13.2 команду умножения MULL3 #4, DIGIT, R0 можно заменить командой сдвига ASHL #2, DIGIT, RO
402 Глава 13 При выполнении команд типа ASHx биты, которые «выталки- ваются» за пределы содержащего их поля, просто теряются. На- пример, в результате выполнения команды ASHL # 10, VALUE, VALUE будут потеряны левые десять битов содержимого поля VALUE, В некоторых случаях может потребоваться циклическое вы- полнение сдвига, при котором биты, «выталкиваемые» из одного конца содержащего их поля, загружаются в него с другого кон- ца. В системе VAX такую операцию можно выполнить с по- мощью команды ROTL (ROTATE LONGWORD — ЦИКЛИЧЕ- СКИЙ СДВИГ ДЛИННОГО СЛОВА), формат которой совпа- дает с форматом команд типа ASHx. В этой команде исполь- зуются те же операнды, что и в командах типа ASHx. Отметим, что для двойных длинных слов и других типов данных команд циклического сдвига не существует. Ниже приведены два примера выполнения команды ROTL, -------1--------1------т-----‘—I Содержимое 00001111101010101110101010100001111 I поля VALUE ROTL «6 VALUE, VALUE 111010101101101010110000011111000017] ^я₽чацщ ROTL «-8, VALUE, VALUE I-------1--------г-:----1-------- Содержимое 111000011|110101011011010101100000111 поля VALUE Команду ROTL можно использовать для перестановки двух слов, входящих в длинное слово: ROTL # 16, адрес, адрес 13.4. Логические операции Основные логические операции над одним битом можно пред- ставить схематически следующим образом: Второй операнд Первый О операнд 1 Операция ИЛИ
Операции над битами и логические операции 403 Кроме операций ИЛИ, ИСКЛЮЧАЮЩЕЕ ИЛИ и И, суще- ствует еще одна базовая логическая операция, называемая «до- полнение». Дополнением бита называется его противоположное значение, т. е. дополнением двоичной единицы является двоич- ный нуль, а дополнением нуля — единица. Перечисленные опера- ции широко используются как в прикладных задачах, непосред- ственно реализующих логические функции (например, при про- ектировании логических схем), так и в программировании, и в частности для выполнения маскирования. Поэтому для их реа- лизации в большинстве ЭВМ предусмотрены специальные команды. ' ' Обычно логические команды вычислительных машин опери- руют с данными стандартного типа, а не с отдельными битами. При этом логические операции выполняются поочередно над всеми битами операнда или операндов. Например, операция И над двумя байтами выполняется как восемь операций И над па- рами соответствующих битов: 10010110 И 10101101 РЕЗУЛЬТАТ 10000100 В системе VAX операция вычисления дополнения может быть выполнена над двоичными данными размером байт, слово или длинное слово командой MCOMB, MCOMW или MCOML соот- ветственно. Обобщенный формат этих команд имеет следующий вид: МСОМх исходные „данные, результат
404 Глава 13 Отметим, что команда MNEGL не эквивалентна команде MCOML. Команда MNEGL вычисляет дополнение значения опе- ранда до 2 (дополнительный код исходного числа), в то время как команда MCOML вычисляет дополнение до 1 (обратный код числа). Операция ИСКЛЮЧАЮЩЕЕ ИЛИ в системе VAX может быть выполнена над двоичными данными размером байт, слово или длинное слово посредством соответствующих двух- или трех- операндных команд. Общее количество таких команд равно шести. Их обобщен- ные форматы имеют следующий вид: XORx2 маска, результат XORx3 маска, исходные жданные, результат Условное обозначение х заменяется буквой В, если размер операндов команды равен байту, буквой W, если этот размер равен слову, и буквой L, если размер — длинное слово. Первый операнд называется маска, поскольку он часто используется для маскирования при поиске различий в значениях операндов. На- пример, в результате выполнения команды XORB3 #~XF0, VALUE, RESULT содержимому поля RESULT присваивается значение 0 только в том случае, когда значение содержимого поля VALUE равно F0 (шестнадцатеричное, число). Каждая единица в двоичном раз- ряде поля RESULT свидетельствует о соответствующем разли- чии сравниваемых операндов. Такая команда может использо- ваться для анализа двоичных данных. Команды системы VAX, базирующиеся на выполнении опера- ций ИЛИ и И, предназначены соответственно для присвоения 0 или 1 отдельным битам обрабатываемых полей. Поэтому у команд, выполняющих операцию ИЛИ, символическое обозна- чение кода операции содержит как составную часть мнемониче- ское сокращение BIS (BIT SET —ПРИСВОИТЬ БИТУ ЗНАЧЕ- НИЕ 1). Что же касается применения для этих целей операции И, то она используется следующим образом: вычисляется допол- нение первого операнда, а затем выполняется операция И над полученным дополнением и вторым операндом. Результатом по- следовательного выполнения этих действий является очистка (заполнение нулями) двоичных разрядов поля результата. По- этому символическое обозначение кода операции таких команд содержит в качестве составной части мнемоническое сокращение BIC (BIT CLEAR — ПРИСВОИТЬ БИТУ ЗНАЧЕНИЕ 0),
Операции над битами и логические операции 405 Команды, выполняющие операцию ИЛИ, могут иметь сле- дующие обобщенные форматы: * л»: BISx2 маска, результат BISx3 маска, исходные-данные, результат Команды типа BISx2 выполняют операцию ИЛИ над содер- жимым полей, адресуемых операндами маска и результат, а команды типа BISx3— над содержимым полей, адресуемых опе- рандами маска и исходные-данные с занесением результата опе- рации в поле результат. Для записи символического обозначе- ния кода операции конкретной команды символ х подлежит за- мене буквой В, если размер операндов равен байту, буквой W, если этот размер равен слову, и буквой L, если размер — длин- ное слово. Для присвоения содержимому отдельных двоичных разрядов поля или их комбинации единичных значений (бит равен 1) мо- жно использовать команду BIS с маской, соответствующие биты в которой равны 1. Например, присвоение 1 битам 4 и 6 байта, размещенного в поле VALUE, можно выполнить с помощью сле- дующей команды: BISB2 #~В01010000, VALUE При выполнении этой команды значение остальных битов поля VALUE остается неизменным. Команды, выполняющие операцию И над дополнением пер- вого операнда и истинным значением второго (команды с мне- моникой BIC как частью имени кода операции), имеют следую- щие обобщенные форматы: В1Сх2 маска, результат В1СхЗ маска, исходные-данные, результат Команды типа В1Сх2 вычисляют дополнение содержимого поля, адресуемого операндами маска, а затем выполняют опера- цию И над полученным дополнением и содержимым поля, адре- суемого операндом результат. Команды типа В1СхЗ вычисляют дополнение содержимого поля, указываемого операндом маска, а затем выполняют операцию И над полученным дополнением и содержимым поля, адресуемого операндом исходные-данные с занесением результата в поле, задаваемое операндом результат. Для указания имени кода операции конкретной команды услов- ное обозначение х заменяется буквой В, если размер операндов равен байту, буквой W, если этот размер равен слову, и буквой L, если размер — длинное слово. В разряды поля, адресуемого операндом результат, которые соответствуют битам со значением 1 в поле, адресуемом операн-
405 Глава 13 дом маска, записываются двоичные нули. Содержимому осталь- них разрядов присваиваются значения соответствующих разря- дов поля, задаваемого вторым операндом (если команду трех» операндная), или они сохраняют предыдущее значение (если команда двухоперандная). Рассмотрим следующий пример, Д Пример 13.Х Применение команды BIC VALUE: .BYTE "Bl 1001101 BICB3 #"B0000llll, VALUE, RESULT В поле RESULT записывается 11000000, поскольку команда BICB3 «очищает» двоичные разряды правого полубайта поля VALUE. Команды типа BIC применяются для присвоения нуле» вых значений содержимому отдельных разрядов или комбинаций разрядов любого байта, слова или длинного слова. Для выполнения операции И над двумя данными (операн- дами) необходимо сначала вычислить дополнение первого опе- ранда. В приводимом ниже примере из поля размером байт вы- деляется содержимое правого полубайта. Д Пример 13.4. Применение операции И для выделения полубайта VALUE: .BYTE "Bl 10Ш00 MASK: .BYTE "Bl 1110000 MCOMB MASK, MASK BICB3 MASK, VALUE, RESULT В поле RESULT записывается 11010000. Отметим, что во мно- гих вычислительных машинах операция И широко используется для выделения отдельных разрядов или строк битов. В вычисли- тельной системе VAX эта задача решается значительно проще с помощью команд EXT, поэтому операции И «спрятаны внутри команд «очистки» двоичных разрядов (присвоения их содержи- мому нулевых значений). Следующий пример иллюстрирует применение различных команд, рассмотренных в данной главе. Здесь показано, как можно преобразовать число с плавающей точкой в форму, при- годную для вывода его значения на печать.
Операции над битами и логические операции 407 Д Пример 13.5 • Постановка задачи Исходные данные-. а) число одинарной точности с плавающей точкой; б) адрес области памяти FRACTION (МАНТИССА) размером длинное слово-, в) адрес области памяти EXPONENT (ПОРЯДОК) размером слово-, г) адрес области памяти SIGN (ЗНАК) размером байт. Искомый результат-, значение мантиссы исходного числа в области FRACTION с учетом ее подразумеваемого старшего раз- ряда; значение порядка исходного числа в естественной форме (а не в форме «с избытком 128») в поле EXPONENT; значение бита знака исходного числа в области SIGN, • Алгоритм решения задачи на псевдокоде Поместить копию числа с плавающей точкой в область FRACTION. Очистить разряды 7—15 и присвоить значение 1 содержимо- му разряда 7 области FRACTION Поменять местами слова содержимого области FRACTION и сдвинуть результирующее содержимое этой области влево на 8 битов Извлечь значение порядка и представить его в естественной форме (а не в форме «с избытком 128») Извлечь знак Конец процедуры • Программа на языке ассемблера ; ПРОЦЕДУРА ФОРМИРОВАНИЯ КОМПОНЕНТОВ ЧИСЛА ; С ПЛАВАЮЩЕЙ ТОЧКОЙ ОДИНАРНОЙ ТОЧНОСТИ ; ИСХОДНЫЕ ДАННЫЕ: ; А. ЧИСЛО С ПЛАВАЮЩЕЙ ТОЧКОЙ ОДИНАРНОЙ ТОЧНОСТИ ; Б. АДРЕС ОБЛАСТИ ПАМЯТИ FRACTION (МАНТИССА) ; РАЗМЕРОМ ДЛИННОЕ СЛОВО ; В. АДРЕС ОБЛАСТИ ПАМЯТИ EXPONENT (ПОРЯДОК) ; РАЗМЕРОМ СЛОВО ; Г. АДРЕС ОБЛАСТИ ПАМЯТИ SIGN (ЗНАК) РАЗМЕРОМ БАЙТ ; ИСКОМЫЙ РЕЗУЛЬТАТ: ЗНАЧЕНИЯ МАНТИССЫ, ПОРЯДКА И ; ЗНАКА ИСХОДНОГО ЧИСЛА В ОБЛАСТЯХ FRACTION, } EXPONENT, SIGN .ENTRY DISMANTLE,''M(R2) INPUT =4 FRACTION=8 EXPONENT == 12
408 Глава 13 SIGN = 16 ; ЗАПИСЬ КОПИИ ЧИСЛА С ПЛАВАЮЩЕЙ ТОЧКОЙ ; В ОБЛАСТЬ FRACTION MOVF INPUT (АР), ©FRACTION (АР) ; ОЧИСТКА РАЗРЯДОВ 7 - 15 И ПРИСВОЕНИЕ ЗНАЧЕНИЯ 1 ; СОДЕРЖИМОМУ РАЗРЯДА 7 ОБЛАСТИ FRACTION BICL2 # ''XFF80, ©FRACTION (АР) BISL2 #'•80, ©FRACTION (АР) • ПЕРЕСТАНОВКА МЕСТАМИ СЛОВ ОБЛАСТИ FRACTION И ; СДВИГ ЕЁ СОДЕРЖИМОГО НА 8 БИТ ВЛЕВО ROTL # 16, ©FRACTION (АР), ©FRACTION (АР) ASHL #8, ©FRACTION (АР), ©FRACTION (АР) ; ИЗВЛЕЧЕНИЕ ПОРЯДКА И ПРЕОБРАЗОВАНИЕ ИЗ ФОРМЫ ; «С ИЗБЫТКОМ 128» В ЕСТЕСТВЕННУЮ ФОРМУ EXTZV #7, #8, INPUT (АР), R2 SUBW3 # 128, R2, ©EXPONENT (АР) • ИЗВЛЕЧЕНИЕ ЗНАКА EXTZV # 15, # 1, INPUT (АР), ©SIGN (АР) RET В системе VAX имеется еще одна группа логических команд, которые выполняют операцию И, однако они не сохраняют ре- зультат. Эти команды только модифицируют биты N и Z при- знака результата. Размеры операндов, над которыми выпол- няется операция И, — байт, слово и длинное слово — определяют три различные формы записи (BITB, BITW и BITL) символиче- ского обозначения кода операции этих команд, именуемых командами типа BIT (BIT TEST — ПРОВЕРКА БИТА). Обоб- щенный формат этих команд имеет следующий вид: BITx маска, исходные „данные Выполняется операция И над двумя операндами и форми- руются соответствующие значения битов Z и N. Результат опе- рации теряется, и ни один из операндов не изменяется. Команды BIT похожи на команды условного перехода типа ВВх с той разницей, что команды BIT проверяют комбинации битов в полях стандартных типов (размеров) и только присваи-
Операции над битами и логические операции 409 вают соответствующие значения содержимому битов-индикато- ров, не осуществляя передачу управления. Рассмотрим следующий пример команды BIT; BITB ф ~В00100101, VALUE Биту Z присваивается значение 1 только в том случае, когда разряды 0, 2 и 5 байта памяти с адресом VALUE содержат нули. Приводимая в этом примере команда никогда не присваи- вает значение 1 биту-индикатору N, поскольку бит знака маски равен нулю. Выводы 1. Строки битов — это данные в определенном смысле фик- тивного типа данных. Можно рассматривать их как данные не- которого особого типа, но по существу это всего лишь фрагмен- ты данных стандартных типов. 2. Строка битов задается базовым адресом, смещением бита относительно базы и длиной, которая всегда меньше 33. 3. Команды типа ВВх осуществляют условный переход в за- висимости от значения определенного заданного бита. 4. Команды типа ВВхх выполняют те же действия, что и команды типа ВВх и, кроме того, модифицируют значение про- веряемого бита. 5. Команды типа FFx используются для поиска в строке би- тов первого бита с указанным значением. 6. Пять команд системы VAX оперируют со строками битов, а не с содержимым отдельных двоичных разрядов. Команды CMPV и CMPZV сравнивают значение строки битов с содержи- мым заданного длинного слова. Команда INSV формирует стро- ку битов из содержимого длинного слова. Команды EXTV и EXTZV помещают строку битов в длинное слово. 7. Команды типа ASHx выполняют арифметический сдвиг влево или вправо содержимого длинного слова или двойного длинного слова. Команда ROTL выполняет циклический сдвиг содержимого длинного слова влево или вправо. 8. Команды типа МСОМх вычисляют дополнение до единицы (обратный код) содержимого поля, адресуемого первым операн- дом. Команды XORx2 и XORx3 выполняют операцию ИСКЛЮ- ЧАЮЩЕЕ ИЛИ. Команды BISx2 и BISx3 выполняют операцию ИЛИ, которая часто используется для присвоения значения 1 одному или нескольким двоичным разрядам адресуемого поля. Команды В1Сх2 и В1СхЗ сначала вычисляют дополнение содер- жимого поля, адресуемого первым операндом, и затем выпол- няют операцию И над этим дополнением и содержимым поля, задаваемого вторым операндом; они часто используются для
410 Глава 13 очистки одного или нескольких двоичных разрядов (присвоения их содержимому нулевых значений). 9. Команды типа BITx проверяют значение содержимого от- дельных разрядов или комбинаций битов. Эти команды не вы- полняют условного перехода, а только модифицируют значения битов признака результата. Новые команды ASHL BICB3 BISW2 CMPZV MCOMW ASHQ BICL2 BISW3 EXTV ROTL ВВС BICL3 BITB EXTZV XORB2 ВВСС BICW2 BITL FFC XORB3 BBCS BICW3 BITW FFS XORL2 BBS BISB2 BLBC INSV XORL3 BBSC BISB3 BLBS MCOMB XORW2 BBSS BISL2 CMPV MCOML XORW3 BICB2 BISL3 Новые термины ДОПОЛНЕНИЕ ИЛИ И ИСКЛЮЧАЮЩЕЕ ИЛИ СТРОКА БИТОВ Вопросы и упражнения 1. Как следует задавать на языке ассемблера операнды, представляющие собой строки битов? 2. В чем разница между командами BBS и BBSS? 3. Каков размер поля представления смещения, используе- мого для адресации точки перехода в команде BBS? 4. Дайте точное описание операций, выполняемых командой FFS, включая модификацию значения бита-индикатора Z. 5. В чем различие между командами CMPV и CMPZV? 6. Почему можно использовать сдвиг вместо умножения на число 2 в соответствующей степени? 7. В чем различие между командами, следующими ниже? ASHL #8, COUNT, COUNT ROTL #8, COUNT, COUNT 8. Выполните следующие операции: а) 11010101 б) 10001000 в) 10101011 И И ИЛИ 10101000 01011011 10001100
Операции над битами и логические операции 4t 1 г) 0110Ш1 д) 10101110 ИЛИ ИСКЛЮЧАЮЩЕЕ ИЛИ 10110001 01100001 е) 10101110 ИСКЛЮЧАЮЩЕЕ ИЛИ 11101010 9. В чем различие действий, выполняемых командами MNEGB и МСОМВ? 10. Напишите команды языка ассемблера, выполняющие опе- рацию И над содержимым слов ALPHA и ВЕТА с записью ре- зультата в поле GAMMA. Напишите и выполните отладку программ на языке ассемб- лера для решения приводимых ниже задач. 11. Исходные данные: длинное слово. Искомый результат: исходное длинное слово, биты которого переставлены в обратном порядке. 12. Исходные данные: два длинных слова. Искомый результат: два длинных слова, представленных как одно двойное длинное слово, содержимое которого сдвинуто влево на пять битов. 13. Исходные данные: целое число размером длинное слово. Искомый результат: исходное число в двоичном коде, для вы- вода которого используется только команда PRINT-A. 14. Предположим, что в некоторой задаче множества пред- ставлены строками битов длиной 256 бит, причем значение каж- дого бита отражает наличие или отсутствие соответствующего элемента множества. Например, если элементы множества — символы кода ASCII и соответствующий символу А бит имеет значение 1, то это означает, что А входит в множество. Напи- шите процедуру, удовлетворяющую перечисляемым ниже усло- виям. Исходные данные (параметры): а) адрес первого байта строки длиной 32 байта, представляю- щей некоторое множество; б) адрес поля размером байт. Искомый результат: содержимое исходного поля размером байт, значение которого равно 1, если множество является пу- стым, и 0 — в противном случае. 15. Напишите процедуру, удовлетворяющую перечисляемым ниже условиям: Исходные данные (параметры) а) адрес первого байта строки длиной 32 байта, представляю- щей множество, элементы которого целые числа в диапазоне 1—256;
412 Глава 13 б) другое множество, определяемое аналогично указанному в п. а); в) адрес поля для размещения строки длиной 32 байта. Искомый результат: строка длиной 32 байта, представляю- щая объединение двух исходных множеств (определяемых в п. а) и б)) и размещенная в поле, адрес которого определен в п. в). 16. Напишите процедуру, удовлетворяющую перечисляемым ниже условиям. Исходные данные (параметры): такие же, как в упр. 15. Искомый результат: строка длиной 32 байта, представляю- щая пересечение двух исходных множеств и размещенная в по- ле, адрес которого определен в п. в). 17. Исходные данные: а) адрес первого байта строки длиной 10 байт, представляющей множество, элементы которого являются целыми числами в диа- пазоне 1—80; б) целое число. Искомый результат: если значение исходного целого числа находится в диапазоне 1—80, необходимо выдать сообщение о том, является ли это число элементом множества; если значение целого числа за пределами диапазона 1—80, то необходимо вы- дать сообщение об ошибке. 18. Исходные данные: 8-разрядное шестнадцатеричное число в коде ASCII Искомый результат: десятичное значение исходного числа, выводимое посредством команды PRINT-L 19. Исходные данные: 8-разрядное шестнадцатеричное число в коде ASCII Искомый результат: двоичное значение исходного числа, вы- водимое посредством команды PRINT-A 20. Исходные данные: целое число размером длинное слово. Искомый результат: количество битов в исходном числе, рав- ных 1. 21. Исходные данные: последовательность десяти целых чи- сел, значения которых в пределах диапазона 0—7. Искомый результат: все исходные числа, упакованные вместе и помещенные в длинное слово, разряды 30 и 31 которого содер- жат нули. 22. Напишите процедуру, удовлетворяющую перечисляемым ниже условиям. Исходные данные (параметры): а) число с плавающей точкой одинарной точности; б) адрес поля размером длинное слово. Искомый результат: исходное число, преобразованное в целое число и размещенное в заднном поле размером длинное слово.
Операции над битами и логические операции 413 Если число с плавающей точкой не помещается в указанное поле, присвоить значение 1 биту — признаку переполнения PSW — слова состояния вызывающей программы. Запрещается использовать команду CVTFL. 23. Напишите процедуру, удовлетворяющую перечисляемым ниже условиям. Исходные данные (параметры): а) целое число размером длинное слово, б) адрес некоторого поля. Искомый результат: содержимое исходного длинного слова, преобразованное в число с плавающей точкой одинарной точ- ности и размещенное по адресу в поле с указанным адресом. За- прещается использовать команду CVTLF.
Глава 14 Средства ввода и вывода Подробное описание средств ввода и вывода системы VAX за- няло бы целую книгу такого же размера, как эта. В данной главе очень кратко рассматриваются структура и некоторые ва- рианты использования одного из способов организации ввода информации в систему VAX и вывода из нее, обеспечиваемого операционной системой VMS. 14.1. Обзор возможностей подсистемы RMS Подсистема обработки записей (Record Management Services — RMS) входит в операционную систему VAX/VMS и реализует один из способов обмена данными между памятью машины и внешними (периферийными) устройствами. Основной единицей обмена при этом способе является запись. В дальнейшем для краткости данная подсистема называется RMS. Средства подсистемы RMS неявно используются в операциях ввода и вывода любых языков программирования высокого уровня, используемых в машйне VAX. В данной главе, однако, рассматриваются обращения к RMS непосредственно из про- грамм на языке ассемблера. Хотя в RMS включены средства для манипулирования дан- ными, размещаемыми как на магнитных лентах, так и на маг- нитных дисках, здесь описываются только операции над дан- ными на магнитных дисках. Данные, хранящиеся на внешних устройствах, могут иметь самую различную структуру, однако в любом случае единицей хранимой информации является запись. Запись — это совокупность элементов данных, или содержимого полей, которые логически связаны в единое целое (например, все сведения, которыми руководитель предприятия располагает об одном служащем). В таком устройстве, как терминал (дис- плей или печатающее устройство), записью является строка. Записи определенной структуры объединяются в последова- тельности, называемые файлами (например, файл записей обо всех служащих предприятия). Накопители на магнитных дисках системы VAX требуют размещения файлов блоками размером 512 байт каждый. Обмен информацией между основной памятью и накопителями на магнитных дисках осуществляется блоками.
Средства ввода и вывода 415 Записи на магнитном диске могут быть представлены в од- ном из трех форматов: фиксированной длины, переменной дли- ны, переменной длины фиксированного набора значений. В этой главе рассматривается только самый простой формат представ- ления записей, т. е. речь идет о записях фиксированной длины. Внутренняя организация файлов может быть последовательной, относительной и индексной. В файле с последовательной организацией, имеющем наибо- лее простую структуру, записи размещаются друг за другом. Возможности обработки ограничены последовательным досту- пом или произвольным доступом по адресу записи в файле; в некоторых языках высокого уровня допускается только последо- вательный доступ. Это означает, что для прочтения десятой за- писи файла необходимо сначала прочитать девять предыдущих. Новые записи добавляются только в конец файла, а для того, чтобы вставить новую запись между двумя существующими, при- ходится создавать новый файл. Одним из достоинств последова- тельной организации файлов является рациональное (без по- терь) использование памяти накопителей на магнитных дис- ках. Файлы с относительной и индексной организацией допускают непоследовательную обработку записей, но требуют более слож- ного программного обеспечения доступа и менее экономно ис- пользуют пространство памяти на магнитных дисках. Все операции ввода и вывода данных в системе VAX осуще- ствляются под управлением системных программных средств, а не программ пользователей. Это существенно для мультипро- граммного режима работы, обеспечивающего одновременный до- ступ к ресурсам ЭВМ многих пользователей. При таком режиме работы управления ресурсами централизовано, поскольку все пользователи имеют доступ к одним и тем же внешним устрой- ствам. Обычно в системе VAX в распоряжении пользователей находится один накопитель на магнитных дисках. Если бы все пользователи непосредственно обращались к программам, выпол- няющим обмен информацией с накопителем на магнитных ди- сках, то в системе воцарился бы полный хас. Поэтому программы пользователей запрашивают выполнение операций ввода и вы- вода, используя макрокоманды для обращения к системным про- граммам RMS. Операции ввода (вывода) подсистемы RMS могут быть и асинхронными, и синхронными. В первом случае управление воз- вращается в программу пользователя сразу после пуска опера- ции; во втором случае управление возвращается программе, за- просившей ввод (вывод), только после завершения операции. Асинхронный ввод (вывод) позволяет программам пользовате- лей совмещать вычисление с операциями обмена данными ме-
416 Глава 14 жду основной и внешней памятью. В данной главе рассматри- ваются только синхронные операции ввода и вывода. Операции RMS подразделяются на две категории: операции над файлами и операции над записями. В операциях над фай- лами обрабатываемыми единицами являются файлы. Многие из этих операций выполняются средствами операционной системы VMS. Из операций над файлами далее рассматриваются сле- дующие: создание нового файла, открытие существующего фай- ла для обработки и закрытие открытого файла. Из операций над записями рассматриваются ввод и вывод записей. 14.2. Блоки управления Блоки управления — это средства связи между программами пользователей и процедурами RMS. В полях этих блоков содер- жится информация об операциях RMS, запрашиваемых про- граммами пользователей, и о коде завершения запрошенных операций. Подсистема RMS использует блоки управления четы- рех типов, однако здесь рассматриваются только два из них: FAB(FILE ACCESS BLOCK —БЛОК ДОСТУПА К ФАЙЛУ) и RAB(RECORD ACCESS BLOCK —БЛОК ДОСТУПА К ЗАПИ- СИ). Структура каждого файла описывается блоком FAB, а структура каждой записи — блоком RAB. В программе пользователя память для необходимых блоков управления должна быть зарезервирована с помощью макро- команд подсистемы RMS, рассматриваемых в разд. 14.2.1. В разд. 14.2.3 описывается макрокоманда, заполняющая необ- ходимой информацией поля блока перед выполнением обработки файла, связанного с этим блоком. 14.2.1. Резервирование памяти для блоков управления Резервирование памяти для блока FAB производится с помощью макрокоманды $FAB. Хотя в этой макрокоманде используются 28 различных параметров, большинство из них имеют значения, присваиваемые по умолчанию. Обычно в макрокоманде указы- вается только несколько фактических параметров. Для обра- ботки существующего (уже созданного) файла в макрокоманде $FAB необходимо задать только значения параметров FAC (FILE ACCESS—ДОСТУП К ФАЙЛУ) и FNM(FILE NAME — ИМЯ ФАЙЛА). Все параметры в макрокомандах являются клю- чевыми. Значение параметра FAC записывается в блок FAB в каче- стве исходного содержимого поля доступа к файлу. Это значе- ние (или значения) представляет операции подсистемы RMS, которые предполагается производить под соответствующим фай;
Средства ввода и вывода 417 лом. Попытка выполнить операцию, не указанную в поле до- ступа к файлу, отвергается подсистемой RMS. Единственными операциями, указание которых необходимо, являются $GET и $PUT. Для этого параметру FAC присваиваются значения GET и PUT соответственно. Например, необходимость использования операции JSGET применительно к существующему файлу указы- вается включением параметра FAC=GET в макрокоманду $FAB для этого файла. Параметр FNM используется для задания имени файла. Имя файла должно быть указано в угловых скобках. В качестве примера рассмотрим следующую макрокоманду $FAB: INFAB: $FAB FAC = GET, FNM = (LIST.DAT) Отметим, что макрокоманды $FAB обычно имеют метки, по- тому что на них должны ссылаться другие макрокоманды под- системы RMS. В приведенном примере содержимое Файла LIST.DAT можно «читать» с помощью макрокоманд $GET при условии, что в блок доступа к файлу включены все другие не- обходимые операции. Макрокоманда $FAB просто резервирует память для блока FAB и заполняет три его поля (значение па- раметра FNM размещается в двух полях, одно из которых пред- назначено для спецификации файла, а другое — для длины спе- цификации). Для файла, который должен быть создан в процессе выпол- нения программы, макрокоманде $FAB необходимы еще три ключевых параметра: ORG, RFM, MRS. Значение параметра ORG (ORGANIZATION — ОРГАНИЗА- ЦИЯ) используется для задания требуемой организации созда- ваемого файла. Для последовательных файлов значение пара- метров ORG должно быть SEQ. Значение параметра RFM(RECORD FORMAT — ФОРМАТ ЗАПИСИ) должно задавать формат записей в файле. Для ука- зания на использование записей фиксированной длины пара- метру RFM присваивается значение FIX. В качестве значения параметра MRS (MAXIMUM RECORD SIZE - МАКСИМАЛЬНАЯ ДЛИНА ЗАПИСИ) должно указы- ваться целое число без знака, размером слово, содержимое кото- рого равняется максимальной длине записей в создаваемом файле. Особенность этого параметра заключается в том, что ука- занное значение не является литералом и поэтому не должно на- чинаться со знака =#=. В то же время некоторые другие макро- команды подсистемы RMS имеют в качестве значений парамет- ров литералы. Отметим, что в макрокоманде $FAB для создаваемого файла не требуется задавать значение параметра FAC, поскольку ма- 14 Зак. 433
418 Глава 14 крокоманда, формирующая файл (^CREATE, см. разд. 14.2.2), включает операцию PUT. В качестве примера рассмотрим следующую макрокоманду $FAB: OUTFAB: $FAB FNM = (DATA. DAT), ORG=SEQ,— RFM = FIX, MRS = 50 Эта макрокоманда определяет структуру последовательного файла DATA.DAT с записями фиксированной длины, максималь- ный размер которых не должен превышать 50 байт. Каждый блок RAB связан с блоком FAB. Память для блока RAB резервируется с помощью макрокоманды $RAB. Хотя в этой макрокоманде используются 18 параметров, почти все они имеют значения, присваиваемые по умолчанию. Практически требуется задать значение только одного параметра. Единственным параметром макрокоманды $RAB, значение которого всегда подлежит заданию, является ключевой параметр FAB. Это значение — адрес блока FAB, с которым должен быть связан данный блок RAB. Например, приводимая ниже4 макро- команда резервирует память для блока RAB, который связан с блоком FAB, размещенным по адресу INFAB. INRAB: $RAB FAB = INFAB 14.2.2. Операции над файлами Для создания нового файла с атрибутами, содержащимися в со- ответствующем блоке FAB, используется макрокоманда ^CREATE. Единственным параметром этой макрокоманды, зна- чение которого всегда должно быть указано явно, является клю- чевой параметр FAB. Значением этого параметра должен быть адрес блока FAB для создаваемого файла. Рассмотрим следую- щий пример: $С RE ATE FAB = OUTFAB Если значением содержимого поля FOP(FILE PROCESS OPTION — РЕЖИМ ОБРАБОТКИ ФАЙЛА) блока FAB явля- ется CIF(CREATE-IF — СОЗДАТЬ -ЕСЛИ), а файл с указан- ным именем уже существует, то указание на выполнение опера- ции по созданию файла игнорируется. Как уже отмечалось, ма- крокоманда ^CREATE делает файл доступным для обработки и разрешает выполнение операций PUT, даже если в макрокоман- де $FAB эта функция не была указана. Макрокоманда $OPEN открывает для обработки существую- щий файл: если файл не открыт, то он обрабатываться не мо- жет. Единственный параметр макрокоманды $OPEN, значение
Средства ввода и вывода 419 которого должно быть указано явно, — ключевой параметр FAB< Значением этого параметра должен быть адрес блока FAB для открываемого файла. Например, файл, для которого сформиро- ван блок FAB в области памяти с адресом INFAB, может быть открыт с помощью следующей макрокоманды: $OPEN FAB = INFAB По макрокоманде JSCLOSE выполняется действие, обратное тому, которое вызывает макрокоманда JSOPEN: файл закры* вается и делается недоступным для последующей обработки. Единственным параметром, значение которого в макрокоманде $ CLOSE необходимо задавать явно, является ключевой пара- метр FAB. Значением этого параметра должен быть адрес блока FAB для файла, который нужно закрыть. Если машинные команды, порожденные макрокомандой $CLOSE, начинают выполняться во время протекания какой- либо другой операции с файлом, то операции его закрытия за- вершаются аварийно и файл останется открытым. Разумеется, такая ситуация невозможна при синхронном режиме выполнения операций. Отметим, что явное задание операций закрытия не обязательно. Все файлы, используемые программой, при завер- шении программы закрываются автоматически. В частности, во время закрытия файла разрываются связи всех блоков RAB с блоками FAB. 14.2.3. Операции над записями Макрокоманда JSCONNECT используется для установления свя- зи между блоками RAB и FAB; если файлы являются последо- вательными, то с каждым блоком FAB может быть связан толь- ко один блок RAB. Макрокоманда ^CONNECT формирует слу- жебные поля в соответствующем блоке RAB. Одно из этих полей предназначено для размещения указателя записи, устанавливае- мого макрокомандой на первую запись. Макрокоманда также резервирует память для требуемого количества буферов, исполь- зуемых как временная память для записей, участвующих в опе- рациях ввода и вывода соответствующего файла. Буферизация применяется для ускорения доступа к файлу. Например, если при вводе данных имеется системный буфер, по- зволяющий разместить две записи файла, то новая запись может считываться одновременно с обработкой содержащейся в буфере предыдущей записи. Отметим, что в этом случае записи извле- каются из файла, хранимого на диске, прежде чем их затребует программа пользователя. Единственным параметром, значение которого должно быть указано в макрокоманде JSCONNECT, яв- ляется ключевой параметр RAB, В качестве этого значения ис- 14*
420 Глава 14 пользуется адрес соответствующего блока RAB. В приводимом ниже примере подобная макрокоманда связывает блок RAB, сформированный ранее в этой главе, с блоком FAB: ^CONNECT RAB = INRAB До начала чтения содержимого файла, хранимого на диске, в соответствующий блок RAB должна быть записана специаль- ная информация. Это выполняется с помощью макрокоманды $RAB_STORE. Первый параметр этой макрокоманды служит для идентификации блока RAB, в который пользователь хочет поместить упомянутую информацию. С помощью макрокоманды $RAB_STORE может быть заполнено много полей блока RAB, но два из них наиболее важны: поле для размещения адреса за- писи и поле длины записи. Ключевые слова для этих двух пара- метров (второго и третьего в макрокоманде) различаются для операций ввода и вывода данных. В операциях вывода для ад- реса записи используется ключевое слово RBF, а для длины за- писи — RSZ. В операциях ввода для адреса записи используется ключевое слово UBF, а для длины записи — USZ. В следующем примере задан буфер пользователя с меткой INBUF и длиной 80 байт: $RAB_STORE RAB = INRAB, UBF = INBUF, USZ = #80 При выполнении этой макрокоманды адрес области памяти INBUF записывается в поле UBF блока RAB, имеющего метку INRAB. Кроме того, в поле USZ того же блока RAB записывает- ся число 80. Отметим, что в отличие от задания в макрокоманде $FAB максимального размера записи числовым значением па- раметра MRS длина записи в макрокоманде $RAB_STORE за- дается литералом. После того как макрокоманда $КАВ_5ТОКЕзаполнит необ- ходимые поля в блоке RAB и блок RAB будет связан с блоком FAB, могут выполняться операции ввода и вывода. Рассмотрим две макрокоманды ввода и вывода подсистемы RMS: $GET и $PUT. Макрокоманда $GET вызывает системную процедуру GET для переноса записи файла в область буфера программы поль- зователя. (На самом деле перенос осуществляется не из файла, а из системного буфера.) При вводе с терминала символ «воз- врат каретки» воспринимается как ограничитель записи. Сим- вол— ограничитель записи помещается в поле STVO, которое является младшим словом поля состояния блока RAB, а длина введенной записи — в слово, смещенное относительно начала блока RAB на значение, непосредственно присваиваемое симво- лическому имени RAB$W_RSZ.
Средства ввода и вывода 421 Единственным параметром макрокоманды $GET, значение которого необходимо задать, является ключевой параметр RAB; это значение должно быть адресом соответствующего блока RAB. Рассмотрим для примера следующий фрагмент программы, использующий зарезервированный пользователем блок INBUF длиной 80 байт: $RAB_STORE RAB = INRAB, UBF = INBUF, USZ = # 80 $GET RAB = INRAB MOVW INRAB + RAB$W_RSZ, LENGTH Эти команды извлекают запись из файла, связанного с блоком RAB (адрес которого INRAB), и помещают длину записи, за- груженной в буфер, в слово LENGTH. Макрокоманда $PUT вызывает системную процедуру PUT для переноса содержимого буфера — области, зарезервированной и заполненной пользователем — в файл. Выполняемые при этом действия фактически обратны действиям, производимым макро- командой $GET. Если файл последовательный, запись всегда помещается в конец. (Допускается размещение новой записи не в конец файла, однако при этом указатель конца файла устана- вливается на позицию, следующую за новой записью, и тем са- мым отсекается остаток файла.) Длина загружаемой в файл за- писи не должна превышать длину, указанную в макрокоманде ^CREATE, формирующей файл. Перед выполнением макрокоманды $PUT в макрокоманде $RAB_STORE должны быть заданы значения двух параметров: адреса помещаемой в файл записи RBF и ее длины RSZ. Рас- смотрим пример, в котором запись длиной 32 байта, находя- щаяся в поле BUF, помещается в файл, блок RAB которого имеет метку OUTRAB. $RAB_STORE RAB = OUTRAB, RBF = BUF, RSZ = #32 $PUT RAB = OUTRAB 14.3. Примеры программ Во время любой операции над файлами или записями возмож* ны различные ситуации, приводящие к возникновению ошибок. Хотя детальное изучение этих вопросов выходит за рам(ки дан* ной книги, рассмотренные выше средства программирования по- зволяют установить сам факт наличия ошибки при выполнении операции и тем самым предотвратить дальнейшую обработку заведомо неверных данных. Код состояния после любой операции над записями или фай- лами помещается в регистр R0, Если код является нечетным чис«
422 Глава 14 лом, то операция завершилась без ошибок. Если код — число четное, возникли какие-то ошибки. Таким образом, для установ- ления наличия ошибок достаточно проверить содержимое раз- ряда 0 регистра R0, используя команду типа BLBx. Рассмотренных выше макрокоманд подсистемы RMS доста- точно для написания учебных программ, включающих операции создания последовательных файлов, заполнения их записями и чтения последних. А Пример 14.1. • Постановка задачи Исходные данные: последовательность строк символов (запи- сей) вводимых с терминала, каждая из которых состоит из сле- дующих полей: а) фамилия (20 символов); б) адрес (30 символов); с) регистрационный номер системы социального обеспечения (9 символов). Признаком конца последовательности записей является стро- ка, начинающаяся символами TJLTIL и содержащая в остальных позициях пробелы. Искомый результат: последовательный файл с именем PEOPLE.DAT, содержащий исходные данные. Хотя поставленная задача довольно проста, сначала приве- дем алгоритм решения на псевдокоде, а затем переведем его описание на язык ассемблера. • Алгоритм решения задачи на псевдокоде Сформировать блоки FAB и RAB для выходного файла Присвоить содержимому счетчика записей нулевое значение Создать выходной файл Ввести фамилию (NAME) WHILE NAME ( ) признак конца DO Ввести адрес и регистрационный номер Поместить запись в выходной файл Увеличить значение содержимого счетчика записей на 1 Ввести следующую фамилию END-DO Вывести число записей, помещенных в файл Закрыть выходной файл Конец программы
Средства ввода и вывода 423 Для организации ввода данных с терминала предполагается использование описанных выше средств ввода и вывода. В разд. 14.4 рассмотрены и продемонстрированы на примере средства ввода и вывода данных с терминала. • Программа на языке ассемблера СОЗДАНИЕ ФАЙЛА ДАННЫХ И ЗАПОЛНЕНИЕ ЕГО ЗАПИСЯМИ ИСХОДНЫЕ ДАННЫЕ: ПОСЛЕДОВАТЕЛЬНОСТЬ ЗАПИСЕЙ, ВВОДИМЫХ С ТЕРМИНАЛА КАЖДАЯ ЗАПИСЬ СОСТОИТ ИЗ СЛЕДУЮЩИХ ПОЛЕЙ: (А) ФАМИЛИЯ (20 СИМВОЛОВ) (Б) АДРЕС (30 СИМВОЛОВ) (В) РЕГИСТРАЦИОННЫЙ НОМЕР СИСТЕМЫ СОЦИАЛЬНОГО ОБЕСПЕЧЕНИЯ (9 СИМВОЛОВ) ИСКОМЫЙ РЕЗУЛЬТАТ: ПОСЛЕДОВАТЕЛЬНЫЙ ФАЙЛ НА ДИСКЕ, СОДЕРЖАЩИЙ ИСХОДНЫЕ ДАННЫЕ .PSECT EXAMPLE, LONG OUT-FAB: $FAB FNM = (PEOPLE. DAT), ORG = SEQ,— RFM = FIX, MRS =59 OUT-RAB: $RAB FAB = OUT_FAB IOBUF: .BLKB 59 ; БУФЕР ДЛЯ ВЫХОДНОЙ ЗАПИСИ REC-NUM: .LONG 0 ; СЧЕТЧИК ЗАПИСЕЙ TRAILER; .BLKB #~A/Z/ [4] ; ПРИЗНАК КОНЦА ВХОДНЫХ ДАННЫХ NAME = IOBUF ADDRESS = IOBUF + 20 SSN = IOBUF + 50 .ENTRY EX_14_1, 0 INIT_IO СОЗДАНИЕ ВЫХОДНОГО ФАЙЛА И УСТАНОВЛЕНИЕ СВЯЗИ ; МЕЖДУ RAB И FAB $CREATE FAB=OUT-FAB ; ЕСЛИ ОШИБКА ПРИ СОЗДАНИИ ФАЙЛА, ТО ВЫВОД СООБЩЕНИЯ ; ОБ ОШИБКЕ И ОСТАНОВ BLBS R0, ОК_1 PRINT-L ~'***ОШИБКА ПРИ СОЗДАНИИ' $EXIT_S • КОНЕЦ ОПЕРАЦИЙ «ЕСЛИ»
424 Глава 14 0К_1: $CONNECT RAB=OUT-RAB ЕСЛИ ОШИБКА ПРИ УСТАНОВЛЕНИИ СВЯЗИ, ТО ; ВЫВОД СООБЩЕНИЯ ОБ ОШИБКЕ И ОСТАНОВ BLBS RO, ОК_2 PRINT.L ~'***ОШИБКА ПРИ УСТАНОВЛЕНИИ СВЯЗИ' $EXIT_S ; КОНЕЦ ОПЕРАЦИИ «ЕСЛИ» ; ВВОД ФАМИЛИИ ОК_2: MOVC5 READ-A # О, IOBUF, #~А/ /, # 59, IOBUF NAME ; ПОКА ФАМИЛИЯ < ) ПРИЗНАК КОНЦА ВЫПОЛНЯТЬ В ЦИКЛЕ LOOP: СМРС5 #20, NAME, #~А/ /, #4, TRAILER BEQL END-LOOP ВВОД АДРЕСА И РЕГИСТРАЦИОННОГО НОМЕРА READ-A ADDRESS READ-A SSN ; ПОМЕЩЕНИЕ ЗАПИСИ В ВЫХОДНОЙ ФАЙЛ $RAB_STORE RAB = OUT-RAB, RBF = IOBUF,— RSZ=#59 $PUT RAB = OUT-RAB ; ЕСЛИ ОШИБКА ПРИ ПОМЕЩЕНИИ ЗАПИСИ В ФАЙЛ, ТО ; ВЫВОД СООБЩЕНИЯ ОБ ОШИБКЕ И ОСТАНОВ BLBS RO, ОК-8 PRINT-L ~'***ОШИБКА ПРИ ПОМЕЩЕНИИ ЗАПИСИ В ФАЙЛ' $EXIT_S • КОНЕЦ ОПЕРАЦИЙ «ЕСЛИ» ОК-3: INCL REC-NUM MOVC5 # 0, IOBUF, #~А/ /, # 59, IOBUF
Средства ввода и вывода 425 READ-A NAME BRW LOOP ; КОНЕЦ ЦИКЛА «ПОКА» END-LOOP: PRINT_L "ЧИСЛО ВВЕДЕННЫХ ЗАПИСЕЙ = ',- REC-NUM $CLOSE FAB=OUT-FAB $EXIT_S .END EX_14_1 Итак, сформирован файл, содержащий фамилии, адреса и регистрационные номера системы социального обеспечения. Те- перь рассмотрим другую программу, проверяющую, правильно ли сформирован файл из таких данных. Эта программа демон- стрирует использование подсистемы RMS для открытия и чте- ния существующего последовательного файла. Д Пример 14.2 о Постановка задачи Исходные данные: последовательный файл PEOPLE.DAT, сформированный программой примера 14.1. Искомый результат: листинг входного файла на терминале. Поскольку данная задача очень проста, описание алгоритма ее решения на псевдокоде не приводится. Основу программы на языке ассемблера составляют следующие операции. При чтении последовательного файла необходимо проверять наличие при- знака «конец файла», который означает, что в файле нет больше записей. В качестве такого признака используется один из ко- дов состояния, который формируется макрокомандой $GET а блоке RAB. Данная информация находится в блоке RAB со сме- щением от начала, определяемым символическим именем RAB$L_STS. Код, соответствующий признаку «конец файла», имеет символическое имя RMS$_EOF. Таким образом, после каждого выполнения макрокоманды $GET производится срав- нение содержимого длинного слова, адрес которого равен сумме адресов RAB и RAB$L_STS, со значением RMS$_EOF, и ес- ли они совпадают, то конец читаемого файла достигнут. • Программа на языке ассемблера : ЧТЕНИЕ ФАЙЛА И ВЫВОД ЕГО НА ТЕРМИНАЛ ; ИСХОДНЫЕ ДАННЫЕ: ПОСЛЕДОВАТЕЛЬНЫЙ ФАЙЛ PEOPLE.DAT^ ; СОЗДАННЫЙ ПРОГРАММОЙ ПРИМЕРА 14.1 ; ИСКОМЫЙ РЕЗУЛЬТАТ: ЛИСТИНГ ВХОДНОГО ФАЙЛА
426 Глава 14 ; НА ТЕРМИНАЛЕ .PSECT EXAMPLE, LONG IN_FAB: $FAB FNM = (PEOPBE.DAT), FAC = GET IN-RAB: $RAB FAB = IN-FAB IN.BUF: .BLKB 59 ; БУФЕР ДЛЯ ВХОДНОЙ ЗАПИСИ REC-NUM: .LONG 0 ; СЧЕТЧИК ЗАПИСЕЙ NAME = IN.BUF ADDRESS = IN.BUF + 20 SSN = IN.BUF + 50 .ENTRY EX_14_2, 0 INIT-IO ; ОТКРЫТИЕ ВХОДНОГО ФАЙЛА И УСТАНОВЛЕНИЕ СВЯЗИ МЕЖДУ ; RAB И FAB $OPEN FAB = IN-FAB ; ЕСЛИ ОШИБКА ПРИ OTKPLITHH ФАЙЛА, ТО ВЫВОД СООБЩЕНИЯ ; ОБ ОШИБКЕ И ОСТАНОВ BLBS RO, ОК-1 PRINT.L ~'***ОШИБКА ПРИ ОТКРЫТИИ ФАЙЛА' $EXIT_S • КОНЕЦ ОПЕРАЦИИ «ЕСЛ11> ОК-1: $CONNECT RAB = IN-RAB ; ЕСЛИ ОШИБКА ПРИ УСТАНОВЛЕНИИ СВЯЗИ, ТО ВЫВОД ; СООБЩЕНИЯ ОБ ОШИБКЕ И ОСТАНОВ BLBS RO, ОК-2 PRINT-L ~'***ОШИБКА ПРИ УСТАНОВЛЕНИИ СВЯЗИ' $EXIT_S ; КОНЕЦ ОПЕРАЦИЙ «ЕСЛИ» ; ЧТЕНИЕ ЗАПИСИ ОК-2: $RAB_STORE RAB = IN-RAB, UBF = IN-BUF, USZ = +59 $GET RAB = IN-RAB ; ЕСЛИ ОШИБКА ПРИ ЧТЕНИИ ЗАПИСИ, ТО ВЫВОД
Средства ввода и вывода 427 ; СООБЩЕНИЯ ОБ ОШИБКЕ И ОСТАНОВ BLBS RO, LOOP PRINT-L “'♦♦♦ОШИБКА ПРИ ЧТЕНИИ ЗАПИСИ' $EXIT-S ; КОНЕЦ ОПЕРАЦИИ «ЕСЛИ» ; ПОКА КОНЕЦ ВХОДНОГО ФАЙЛА НЕ ДОСТИГНУТ, ВЫПОЛНЯТЬ ; В ЦИКЛЕ LOOP: CMPL IN-RAB + RAB$L_STS, # RMS$_EOF BNEQ IN-LOOP BRW END-LOOP IN-LOOP: ; ВЫВОД ЗАПИСИ НА ТЕРМИНАЛ PRINT-A ‘‘'ФАМИЛИЯ:', #20, NAME PRINT-A '‘'АДРЕС:', #30, ADDRESS PRINT-A •''РЕГИСТРАЦИОННЫЙ НОМЕР:', #9, SSN PRINT-L ' INCL REC-NUM $GET RAB = IN-RAB ; ЕСЛИ ОШИБКА ПРИ ЧТЕНИИ ЗАПИСИ, ТО ВЫВОД СООБЩЕНИЯ ; ОБ ОШИБКЕ И ОСТАНОВ BLBS RO, OK-3 PRINT-L “'♦♦♦ОШИБКА ПРИ ЧТЕНИИ ЗАПИСИ' $EXIT_S ; КОНЕЦ ОПЕРАЦИИ «ЕСЛИ» ОК-3: BRW LOOP ; КОНЕЦ ЦИКЛА «ПОКА» END-LOOP: PRINT-L “' ' PRINT-L ''ЧИСЛО ПРОЧИТАННЫХ ЗАПИСЕЙ = ',- REC.NUM $EXIT_S .END ЕХ_14_2
428 Глава 14 14.4. Операции ввода и вывода данных с помощью терминала В этом разделе показано, как ввести данные с терминала и вы- вести их на терминал. Эти операции уже неоднократно исполь- зовались в примерах, приводимых в предыдущих главах и раз- делах, однако все детали их выполнения были «скрыты» за простым по форме указанием на использование пакета ввода- вывода (см. приложение Г). Операции ввода-вывода с помощью терминала практически не отличаются от аналогичных операций с последовательными файлами, рассматриваемыми в данной главе. При вводе и вы- воде с помощью терминала используются стандартные файлы, которые всегда существуют и, таким образом, их не нужно со- здавать. В макрокомандах $FAB просто указываются стандарт- ные имена файлов. В операционной системе стандартными име- нами входного и выходного файлов являются SYS$INPUT и SYSJSOUTPUT соответственно. Указание имени SYS$INPUT в качестве значения параметра FNM макрокоманды $FAB по- зволяет осуществлять ввод с терминала. Аналогично для вы- вода на терминал параметру FNM макрокоманды $FAB долж- но быть присвоено имя SYS$OUTPUT. Учитывая специфику представления данных на терминале, необходимо включать в выводимые данные символы кода ASCII, именуемые «возврат каретки» и «перевод строки», для разделения строк. Это можно сделать дополнительной макрокомандой $PUT, которая выве- дет символы «возврат каретки» и «перевод строки». Десятичные значения кодов этих символов равны соответственно 13 и 10. Программа приводимого ниже примера поясняет организа- цию ввода и вывода информации с помощью терминала. Эта программа почти целиком состоит из операций ввода и вывода: первые выполняют ввод одной строки символов с терминала, вторые — выводят эту строку обратно на терминал. Д Пример 14.3 • Постановка задачи Исходные данные-, вводимая с терминала строка, содержа- щая не более 80 символов. Искомый результат: исходная строка символов, выведенная обратно на терминал. Как и в предыдущем примере, простота алгоритма решения задачи позволяет не приводить его описание на псевдокоде. • Программа на языке ассемблера ; ОПЕРАЦИИ ВВОДА И ВЫВОДА ДАННЫХ НА ТЕРМИНАЛЕ
Средства ввода и вывода 429 ; ИСХОДНЫЕ ДАННЫЕ: ВВОДИМАЯ С ТЕРМИНАЛА СТРОКА СОДЕРЖАЩАЯ НЕ БОЛЕЕ 80 СИМВОЛОВ ; ИСКОМЫЙ РЕЗУЛЬТАТ: ИСХОДНАЯ СТРОКА, ВЫВЕДЕННАЯ НА ТЕРМИНАЛ .PSECT INFAB: $FAB INRAB: $RAB OUTFAB: $FAB OUTRAB: $RAB INBUF: .BYTE CRLF: .BYTE .ENTRY INIT-IO EXAMPLE, LONG FAC = GET, FNM = (SYS$INPUT> FAB = INFAB FAC = PUT, FNM = (SYS$OUTPUT) FAB = OUTRAB лА/ / [80] ; БУФЕР ДЛЯ ВХОДНОЙ ЗАПИСИ 13, 10 ; ОБЛАСТЬ ПАМЯТИ С КОДАМИ ; СИМВОЛОВ ;«ВОЗВРАТ КАРЕТКИ» И ; «ПЕРЕВОД СТРОКИ» ЕХ-14-3, 0 . ОТКРЫТИЕ ВХОДНОГО И ВЫХОДНОГО ФАЙЛОВ • И УСТАНОВЛЕНИЕ СВЯЗЕЙ МЕЖДУ RAB И FAB $OPEN FAB = INFAB $OPEN FAB = OUTFAB ; ЕСЛИ ОШИБКА ПРИ ОТКРЫТИИ ФАЙЛОВ, ТО ВЫВОД 5 СООБЩЕНИЯ ОБ ОШИБКЕ И ОСТАНОВ BLBS RO, OK-1 PRINT-L ~'***ОШИБКА ПРИ ОТКРЫТИИ ФАЙЛА' $EXIT_S ; КОНЕЦ ОПЕРАЦИЙ «ЕСЛИ» ОК-1: $CONNECT RAB = INRAB $CONNECT RAB=OUTRAB : ЕСЛИ ОШИБКА ПРИ УСТАНОВЛЕНИИ СВЯЗИ, ТО ВЫВОД •• СООБЩЕНИЯ ОБ ОШИБКЕ И ОСТАНОВ ’ BLBS RO, OK-2 PRINT_L л/***ОШИБКА ПРИ УСТАНОВЛЕНИИ СВЯЗИ' $EXIT_S ; КОНЕЦ ОПЕРАЦИЙ «ЕСЛИ» ; ВВОД ИСХОДНОЙ СТРОКИ
430 Глава 14 ОК-2: $RAB_STORE RAB == INRAB. UBF = INBUF, USZ = #8C $GET RAB = INRAB 9 ; ЕСЛИ ОШИБКА ПРИ ВВОДЕ СТРОКИ, ТО ВЫВОД СООБЩЕНИЯ ; ОБ ОШИБКЕ И ОСТАНОВ BLBS RO, OK-3 PRINT-L ‘"'♦♦♦ОШИБКА ПРИ ВВОДЕ СТРОКИ' $EXIT_S ; КОНЕЦ ОПЕРАЦИЙ «ЕСЛИ» ; ВЫВОД СИМВОЛОВ «ВОЗВРАТ КАРЕТКИ», «ПЕРЕВОД СТРОКИ» ; И ИСХОДНОЙ СТРОКИ ОК-3 $rab-store rab = outrab, rbf = crlf,-s; RSZ = #2 $PUT RAB = OUTRAB $RAB_STORE RAB = OUTRAB, RBF = INBUF,—? RSZ = #80 $PUT RAB = OUTRAB J ; ЕСЛИ ОШИБКА ПРИ ВЫВОДЕ СИМВОЛОВ ИЛИ СТРОКИ, ; ТО ВЫВОД СООБЩЕНИЯ ОБ ОШИБКЕ И ОСТАНОВ BLBS RO, OK-4 PRINT-L "'♦♦♦ОШИБКА ПРИ ВЫВОДЕ' $EXIT-S ; КОНЕЦ ОПЕРАЦИЙ «ЕСЛИ» Отметим, что в программу включена макрокоманда INIT-IO, а для вывода сообщений об ошибках используется макрокоман- да PRINT-L. Это сделано для упрощения программы. Полное описание подсистемы RMS можно найти в следую- щих руководствах по эксплуатации системы VAX-11 фирмы Digi- tal Equipment Corporation: «Введение в подсистему управ- ления данными VAX-11»(DEC#АА — D024C — ТЕ), «Подсисте- ма управления данными VAX-П. Руководство пользователя» 4DEC#АА — D781C — ТЕ), «Подсистема управления данными
Средства ввода и вывода 431 ЭВМ VAX-11. Справочное руководство» (DEC#AAD031C — ТЕ) Перечень возможностей используемого в программах данной книги пакета ввода-вывода приведен в приложении Г. Содер- жащиеся там примеры аналогичны рассмотренным в данной главе. Выводы 1. Подсистема RMS представляет собой реализацию одного из способов организации ввода и вывода и является составной частью операционной системы VMS ЭВМ VAX. 2. Данные хранятся на магнитных дисках в виде файлов, состоящих из записей, которые в свою очередь являются сово- купностью данных. Все операции ввода и вывода данных в си- стеме VAX выполняются путем выдачи операционной системе запросов на обслуживание. Для этой цели подсистема RMS рас- полагает набором макрокоманд. 3. Блоки управления являются средством передачи входных и выходных параметров между программами пользователей и системными обслуживающими программами. Каждый файл опи- сывается блоком FAB, записи файла — блоком RAB. Макро- команда $FAB резервирует область памяти для размещения блока FAB и заполняет некоторые из ее полей. Макрокоманда $RAB резервирует область памяти для блока RAB и заполняет некоторые из полей этой области. 4. Макрокоманда ^CREATE применяется для создания но- вого файла в соответствии со значением содержимого полей блока FAB. Макрокоманда $OPEN подготавливает файл для использования. Макрокоманда ^CONNECT предназначена для установления связи между блоком RAB и файлом. 5. Макрокоманда $RAB_STORE заполняет поле блока RAB во время выполнения программы. Макрокоманда $GET пере- носит запись из файла в буферную область. Макрокоманда $PUT переносит запись из буферной области в файл. 6. Операции ввода и вывода данных с помощью терминала производятся в основном так же, как и с файлами на диске. Однако в этом случае для файлов используются стандартные имена SYSgINPUT и SYSgOUTPUT. Новые команды gCLOSE ^CONNECT ^CREATE $FAB gPUT $GET $RAB gOPEN $RAB_STORE
432 Глава 14 Новые термины Асинхронные операции Блоки доступа к записи Блоки доступа к файлам Блоки управления Операции над записями Операции над файлами Поля Последовательная организация файла Записи Синхронные операции Файлы Вопросы и упражнения 1. Объясните, почему пользователям не предоставляется воз- можность непосредственного обращения к периферийным устройствам. 2. Каково назначение блоков управления в подсистеме RMS? 3. Что такое блок FAB и каково его назначение? 4. Что такое блок RAB и каково его назначение? 5. Нужно ли в программе использовать макрокоманды ^CREATE и $OPEN для одного файла? 6. Чем отличается заполнение полей RAB с помощью мак- рокоманды $RAB от запоолнения этих полей посредством мак- рокоманды $RAB_STORE? 7. Какова организация файла SYS$INPUT? Об этом пря- мо ничего не сказано в данной главе, но попробуйте дога- даться. 8. Зачем в подсистеме RMS имеется возможность работы с файлами, организация которых отличается от последователь- ной? 9. Является ли литералом константа, представляющая мак- симальную длину записи в макрокоманде $FAB? 10. Является ли литералом константа, представляющая дли- ну записи для занесения в поле блока RAB и задаваемая в макрокоманде $RAB_STORE? Напишите и выполните отладку программы на языке ас- семблера для решения следующих задач, 11. Исходные данные: последовательность менее чем три- дцати имен, длиной по 20 символов, вводимых с терминала, завершаемая именем с символом Z в первых четырех позициях. Искомый результат: последовательный файл на диске, со- держащий входные данные, расположенные в алфавитном по- рядке. 12. Исходные данные: файл упр. И. Искомый результат: исходные данные, выведенные на тер- ^минал в обратном алфавитном порядке,
Средства ввода и вывода 433 13. Исходные данные: последовательность менее чем 20 на- боров данных, вводимых с терминала. Каждый набор содержит следующее: а) фамилия (20 символов); б) адрес (30 символов); в) номер телефона (целое число размером длинное слово). Искомый результат: два последовательных файла, каждый из которых содержит исходные данные. В первом файле записи расположены в алфавитном порядке. Во втором файле записи расположены в порядке возраста* ния номеров телефонов. 14. Исходные данные: а) файл упр. 11. б) последовательность вводимых с терминала имен, каждое из которых содержит не более 20 символов, количество имен ме- нее 10. Искомый результат: новый последовательный файл, полу- ченный путем вставки новых имен, введенных с терминала, на соответствующие им позиции. 15. Исходные данные: последовательность чисел размером длинное слово каждое. Искомый результат: сумма исходных чисел. Замечания. Приводимый в приложении Г пакет ввода-выво- да применять для решения этой задачи нельзя; конец входного файла можно обнаружить по значению поля состояния, так как это делается в программе примера 14.2.
Глава 15 Остальные команды системы VAX В данной главе описываются команды VAX-11, оставшиеся не рассмотренными при изложении материала предыдущих глав. Причиной этого послужило то что они либо используются очень редко, либо не соответствуют тематике этих глав. Основное внимание уделяется командам обработки очередей данных, арифметики повышенной точности, организации структуры вы- бора направления хода вычислений, преобразования кодов сим- волов. 15.1. Очереди Очереди представляют собой одну из наиболее распространен- ных структур организации данных. В повседневной жизни ча- сто приходится иметь дело с очередями, например в кафетерии. Поскольку задачи на ЭВМ решаются путем моделирования реальных жизненных ситуаций, представляется важной возмож- ность моделирования очередей с помощью ЭВМ. Очереди также широко используются в операционных си- стемах. Последние — это прежде всего средства управления ре- сурсами, поэтому очереди могут применяться, например, для хранения запросов на ресурсы. В отличие от большинства дру- гих вычислительных систем язык ассемблера системы VAX рас- полагает командами для работы с очередями. Очереди, как и стеки, могут быть реализованы либо путем смежного (непрерывного) размещения элементов, либо в соот- ветствии с определенными правилами их рассредоточенного раз- мещения. При смежном расположении элементов очереди логи- ческое «соседство» элементов предполагает их физическое рас- положение в смежных полях. Основным недостатком смежного размещения элементов очереди (как и других списковых струк- тур), является необходимость перемещения данных в структуре при включении внутрь нового или удаления имеющегося внутри элемента. Выход из положения обеспечивается применением рассредоточенного размещения элементов структуры, при кото- ром логическая последовательность элементов поддерживается с помощью указателей местоположения этих элементов. По-
Остальные команды системы VAX 435 скольку в такой структуре элементы связаны друг с другом, их часто называют связанными списками. Очереди, обрабатываемые системой VAX, представляют со- бой кольцевые двунаправленные списки. В такой структуре ка- ждый элемент содержит два указателя, т. е. участвует в двух связях. Очередь имеет головной элемент, содержащий два длин- ных слова, каждое из которых является указателем местополо- жения некоторого элемента. Каждый элемент очереди состоит из трех частей: ссылки вперед, ссылки назад и данных. Обе ссылки являются адресами. Ссылка вперед, которую будем на- зывать FLINK, содержит адрес элемента, логически следую- щего в очереди за данным элементом. Поле FLINK последнего Рис. 15.1. Структура очереди четырехбуквенных имен. элемента в очереди содержит адрес головного элемента. Ссыл ка назад, которую будем называть BLINK, содержит адрес эле- мента очереди, логически предшествующего данному. Поле BLINK первого элемента в очереди содержит адрес головного элемента. Поле FLINK занимает первое длинное слово в эле- менте, а поле BLINK — второе; адресом элемента является ад- рес поля FLINK. Поле данных размещается следом за полем BLINK. На рис. 15.1 показана логическая структура очереди из трех элементов, содержащих в поле данных четырехбуквенные име- на. Обратите внимание, что головной элемент не содержит поля данных. Этот элемент состоит только из полей FLINK и BLINK. Основное назначение головного элемента — упростить моде- лирование пустых очередей. В головном элементе пустой очереди обе ссылки содержат адрес самого головного элемента, как по- казано на рис. 15.2. Элементы добавляются только в конец очереди («в хвост»), а удаляются только из начала («с головы»),
436 Глава 15 В операционной системе машины VAX очереди часто при- меняются для ведения совместно используемых списков. В этих случаях очереди реализуются в несколько более общем виде. Хотя команды добавления и удаления элементов называются так же, как в случае операций только с очередями, фактически они рассчитаны на добавление и удаление элементов из произ- вольных двунаправленных списков. В таких списках элементы могут быть удалены или вставлены в любом месте. Команды манипулирования очередями имеют следующий обобщенный формат: INSQUE вставляемый-элемент, предшествующий_элемент REMQUE удаляемый__элемент, адрес Команда INSQUE (INSERT IN QUEUE — ВКЛЮЧЕНИЕ В’ ОЧЕРЕДЬ) добавляет элемент, заданный первым операндом, в двунаправленный список сразу за элементом, адрес которого задан вторым операндом. Если в качестве второго операнда команды INSQUE указан адрес последнего элемента очереди, новый элемент добавляется «в хвост» (операция enqueue — по- ставить в очередь). Однако новый элемент может быть разме- щен и в произвольной позиции списка. Если список пуст (т. е. добавляемый элемент — первый в списке), то биту Z признака результата присваивается значение 1, в противном случае — О, Команда REMQUE (REMOVE FROM QUEUE — УДАЛЕНИЕ ИЗ ОЧЕРЕДИ) удаляет элемент, заданный первым операндом, из двунаправленного списка и помещает его адрес в поле, за- даваемое вторым операндом. Если в качестве первого операнда команды REMQUE указан первый элемент списка, то элемент удаляется «с головы» (операция dequeue — удалить из очере- ди). Однако с помощью команды REMQUE можно удалить из списка любой элемент. Если удаляемый элемент — единствен-
Остальные команды системы VAX 437 ’.NEW 921 INSQUE NEW,@LISTiA+4 Рис. 15.3. Добавление элемента в конец списка.
438 Глава 15 REMQUE BL 1ST.A,TEMP Рис. 15.4. Удаление элемента из начала списка,
Остальные команды системы VAX 439 ный в списке, то биту Z признака результата присваивается значение 1, в противном случае — 0. Если обрабатываемый спи- сок пуст, фиксируется ошибка путем присвоения значения 1 биту V. Если список не пуст, биту V присваивается значение 0. Поскольку команды INSQUE и REMQUE часто используют- ся отдельными процессами, работающими с общим списком, то при их реализации предусмотрены некоторые специальные воз- можности, рассмотрение которых, однако, выходит за рамки данной книги. Необходимую информацию можно найти в спра- вочнике по архитектуре вычислительной системы VAX. Теперь проиллюстрируем действие команд INSQUE и REMQUE. Пусть каждый элемент очереди состоит из трех длинных слов, причем поле данных содержит целое число раз- мером длинное слово (два других длинных слова являются по- лями указателей FLINK и BLINK). На рис. 15.3 показано выполнение операции enqueue, состоя- щее из следующих четырех этапов: 1) присвоение указателю BLINK элемента NEW значения ука- зателя BLINK элемента LIST-A; 2) присвоение указателю FLINK элемента, который был по- следним (на него указывает BLINK элемента LIST-A), значе- ния адреса элемента NEW; 3) присвоение указателю FLINK элемента NEW значения ад- реса элемента LIST-A (головной элемент); 4) присвоение указателю BLINK элемента LIST-A (головной элемент) значения адреса элемента NEW. На рис. 15.4 показано выполнение операции dequeue, состоя- щее из следующих трех этапов: 1) присвоение указателю TEMP значения FLINK элемента LIST-A; 2) присвоение указателю FLINK элемента LIST-A (голов- ной элемент) значения FLINK элемента TEMP; 3) присвоение указателю BLINK элемента, на который ука- зывает FLINK элемента TEMP, значения адреса элемента LIST-A (головной элемент). 15.2. Локальные метки Локальные метки действуют в ограниченной области програм- мы на языке ассемблера. Благодаря тому, что область их опре- деления ограничена, такие метки можно использовать повторно без опасности возникновения многократного определения той же метки. Метки, формируемые при создании макрорасшире- ния, также являются локальными. По форме все локальные метки представляют собой деся* личные числа, значения которых не выходят за пределы диа*
440 Глава 15 пазона 1—65535. За таким числом следует знак $. Метки, пред* ставляемые десятичными числами в диапазоне 30000—65535, зарезервированы для использования в макрорасширениях. Мет- ки в виде десятичных чисел от 1 до 29999 предназначены для применения в программах пользователей. Фрагмент программы на языке ассемблера, в пределах ко- торого использование данной локальной метки допустимо (она определена) называется блоком локальной метки. Границы та- кого блока могут быть установлены несколькими способами. Начало блока локальной метки задается обычной меткой, ди- рективой .PSECT или директивой .ENABLE с параметром LOCAL-LABEL. Конец блока локальной метки задается обыч- ной меткой, директивой .PSECT или директивой .DISABLE с па- раметром LOCAL-LABEL, за которым следует обычная метка. Директива .ENABLE с параметром LOCAL-LABEL отме- няет действие обычных меток в качестве ограничителей. Блоки локальных меток, которые начинаются с такой директивы, за- канчиваются только при появлении первой обычной метки, сле- дующей за директивой .DISABLE с параметром LOCAL-LABEL. Однако обычно границы блоков локальных меток определяют- ся с помощью обычных меток. Следующий фрагмент программы демонстрирует использо- вание локальных меток: LOOP: 10$: OUT-LOOP: 10$: LOOP2: Поскольку локальная метка 10$ используется в двух раз- личных блоках локальных меток, недопустимая ситуация мно- гократного определения метки не возникает. Во избежание пу- таницы локальные метки не помещаются в обычную таблицу символических имен программы. 15.3. Структуры выбора направления хода вычислений Часто алгоритм решения задачи требует выбора направления хода вычислений не из двух, а из многих возможных направ-. лений. Конструкция псевдокода IF позволяет выбрать одно на-
Остальные команды системы VAX 441 правление из двух возможных. Большинство языков програм- мирования высокого уровня располагает средствами многоаль- тернативного выбора передачи управления (направления хода вычислений), например конструкция CASE в языке Паскаль или конструкции SWITCH в языке Си. Команда системы VAX, реализующая альтернативный вы- бор, не так сложна, как может показаться. Обобщенный фор- мат этой команды (типа CASEx) имеет следующий вид: CASE* переключатель, база, предел смещение [0] смещение [1] смещение [п] Операнд переключатель является средством выбора направ- ления передачи управления (ветви вычислительного процесса). Значение этого операнда определяет выбор величины смещения (целого числа размером слово), которое добавляется к содер- жимому счетчика команд (СК). Операнд база содержит наи-< меньшие допустимые значения переключателя, значение базы вычитается из значения переключателя для формирования ин- декса с нулевым минимальным значением. Операнд предел ис- пользуется для обнаружения ошибки, когда переключатель при- нимает значение, выходящее за допустимый диапазон. Если переключатель принимает недопустимое значение, управление передается по адресу, следующему сразу за последним значе- нием смещения. В этом месте обычно размещается команда пе- редачи управления процедуре обработки ошибки, хотя иногда вместо обработки ошибки просто печатается сообщение об ошибке. Команда типа CASEx может использоваться в виде одной из своих трех модификаций: CASEB для операндов размером байт, CASEW для операндов размером слово и CASEL для операндов размером длинное слово. Отметим, что независимо от используемой модификации команды типа CASEx величина смещения всегда представлена целым числом размером слово. Вероятно, лучшим объяснением назначения и иллюстрацией выполнения команды типа CASEx является совместное рассмот- рение функционирования оператора CASE языка Паскаль и его эквивалента на языке ассемблера.
442 ' Глава 15 ’ Д Пример 15.1. Использование оператора CASE языка Паскаль CASE CHOOSE OF BEGIN 1: CAT1 := CAT1 + 1; 2: CAT2 := CAT2 + 1; 3: CAT3 := CAT3 4-1 OTHERWISE WRITELN ('ошибка при переключении, CHOOSE = ', CHOOSE) END Соответствующий фрагмент программы на языке ассембле- ра имеет следующий вид: CASEL CHOOSE, # 1, #2 1$: .WORD 10$ - 1$ .WORD 20$ — 1$ .WORD 30$ - 1$ PRINT-L ^'ОШИБКА ПРИ ПЕРЕКЛЮЧЕНИИ, CHOOSE = ', CHOOSE BRW 40$ 10$; INCL CAT1 BRW 40$ 20$: INCL CAT2 BRW 40$ 30$: 40$: INCL CAT3 Обратите внимание, что значение операнда предел на еди- ницу меньше, чем число различных смещений. Если бы в дан- ном случае база и предел были соответственно равны #! и #=3, то недопустимое значение переключателя обусловило бы переход по адресу, на два байта превышающему начало про- цедуры печати сообщения об ошибке. Эта распространенная ошибка часто является причиной сбоев во время выполнения программы. Если фрагменты программы на языке ассемблера, которым передается управление, содержат большое число команд, то в целях повышения наглядности желательно представить их в виде подпрограмм. 15.4. Команды арифметики целых чисел с повышенной точностью В мини-ЭВМ первых поколений, имевших машинное слово дли- ной 8, 12 или 16 бит, часто возникала проблема выполнения арифметических операций, в которых для представления чис- лового значения каждого операнда требовалось несколько ма- шинных слов. Поскольку система VAX располагает арифмети- ческими командами, оперирующими с целыми числами разме-
Остальные команды системы VAX 443 ром 32 бит, подобные проблемы возникают реже. И все-таки иногда требуется складывать или вычитать числа, размер ка- ждого из которых более 32 бит. Для этих целей в набор команд VAX включены команды сложения и вычитания двух длинных слов с использованием бита-индикатора переноса. Эти команды имеют следующий обобщенный формат: ADWC слагаемое, сумма SBWC вычитаемое, разность Команда ADWC(ADD WITH CARRY —СЛОЖЕНИЕ С ПЕ- РЕНОСОМ) аналогична команде ADDL2 с той разницей, что значение бита-индикатора переноса добавляется к сумме. Команада SBWC (SUBTRACT WITH CARRY —ВЫЧИТА- НИЕ С ПЕРЕНОСОМ) аналогична команде SUBL2 с той раз- ницей, что значение бита-индикатора переноса вычитается из второго операнда. Поскольку биту-индикатору переноса при- сваивается значение 1 в результате заёма в ходе предыдущего вычитания, имеется возможность организовать вычитание с по- вышенной точностью. Пусть два целых числа размером длинное слово каждое размещены в областях памяти ALPHA и ВЕТА соответственно, и нужно вычислить значение арифметического выражения 2-ALPHA—ВЕТА с записью результата в область GAMMA. Пусть длина обоих операндов — содержимого областей ALPHA и ВЕТА — одинакова и записана в области памяти LEN разме- ром длинное слово, а область GAMMA имеет достаточную дли- ну для размещения результата. Тогда приведенная ниже про- грамма вычисляет GAMMA = 2 - ALPHA - BETA Д Пример 15.2. Арифметические операции с повышенной точностью ; ВЫЧИСЛЕНИЕ 2*ALPHA С ЗАПИСЬЮ РЕЗУЛЬТАТА В ОБЛАСТЬ ; GAMMA DIVL3 #4, LEN, R6 MOVC3 R6, ALPHA, GAMMA ; ПРИБАВЛЕНИЕ ПЕРВОГО ДЛИННОГО СЛОВА ОБЛАСТИ ALPHA ; К СОДЕРЖИМОМУ ОБЛАСТИ GAMMA ADDL2 ALPHA, GAMMA ; ДЛЯ REG;=1 ДО LEN-1 ВЫПОЛНЯТЬ В ЦИКЛЕ
444 Глава 15 MOVL # 1, R6 SUBL3 # 1, LEN, LIMIT LOOP1: ; ПРИБАВЛЕНИЕ К СОДЕРЖИМОМУ GAMMA СЛЕДУЮЩЕГО • ДЛИННОГО СЛОВА ADWC ALPHA[R6], GAMMA[R6] AOBLEQ LIMIT, R6, LOOP1 • КОНЕЦ ЦИКЛА «ДЛЯ» ; ВЫЧИТАНИЕ ИЗ СОДЕРЖИМОГО ОБЛАСТИ GAMMA ПЕРВОГО ; ДЛИННОГО СЛОВА I SUBL2 BETA, GAMMA ДЛЯ REG: = 1 ДО ВЫПОЛНЯТЬ В ЦИКЛЕ * MOVL # 1, R6 LOOP2: 5 ; ВЫЧИТАНИЕ ИЗ СОДЕРЖИМОГО GAMMA СЛЕДУЮЩЕГО ДЛИННОГО СЛОВА SBWC BETA[R6], GAMMA[R6] AOBLEQ LIMIT, R6, LOOP2 ; КОНЕЦ ЦИКЛА «ДЛЯ» Эта программа написана в предположении, что запись опе- рандов в память начинается с размещения младших разрядов, как это принято в системе VAX. Если бы длины операндов были фиксированы и относительно невелики, можно было обой- тись без циклов и просто использовать режим косвенной адре- сации с автоматическим увеличением адреса, что позволило бы сократить объем памяти, требуемой для размещения програм- мы, и увеличить скорости ее выполнения. 15.5. Перекодирование символов В этом разделе рассматриваются две команды перекодирова- ния строк символов. Эти команды применяются прежде всего для преобразования строк символов, представленных в коде ASCII, в строки символов в коде EBCDIC (EXTENDED BINARY- CODED DECIMAL INTERCHANGE CODE — РАСШИРЕН- НЫЙ ДВОИЧНО-ДЕСЯТИЧНЫЙ КОД ОБМЕНА ДАННЫМИ)
Остальные команды системы VAX 445 и обратно. Однако иногда с их помощью осуществляется пере- кодирование подобной информации, представляемой в других кодах, отличных от указанных выше, являющихся наиболее ча- сто употребляемыми. Одна из рассматриваемых команд перекодирования обраба- тывает строки символов фиксированной длины. Другая команда выполняет преобразование до возникновения одной из двух си- туаций: либо в таблице перекодировки встретится особый сим- вол, либо оказываются обработанными (исчерпаны) все сим- волы обрабатываемой строки. Команда MOVTC(MOVE TRANSLATED CHARACTERS — ПЕРЕСЫЛКА СИМВОЛОВ С ПЕРЕКОДИРОВАНИЕМ) по- хожа на команду MOVC5. Единственное отличие заключается в том, что символы преобразуются путем использования их в качестве индексов таблицы перекодировки. Команда MOVTC имеет следующий обобщенный формат: MOVTC длина „исходной „строки, адрес „исходной „ст роки, символ-заполнитель, таблица, длина„поля„раз- мещения „результата, адрес „поля „размещения „ результата Все эти операнды аналогичны операндам команды MOVC5, за исключением операнда таблица, который задает адрес таб- лицы перекодировки длиной 256 байт. Первые два операнда определяют строку, которая должна быть перекодирована и пе- реслана. Последние два операнда определяют область, куда должен быть помещен результат. Операнд символ-заполнитель является символом, которым дополняется результирующая стро- ка, если размер поля, предоставляемого для размещения ре- зультата, указывается больше длины исходной строки. Если же исходная строка не умещается в предоставляемой ей области, ее «лишние» символы игнорируются. Таблица перекодировки, указываемая в команде MOVTC, используется почти так же, как и при выполнении команд CVTPT и CVTTP. Исходный символ рассматривается как ин- декс таблицы перекодировки, а результатом перекодировки яв- ляется значение индексируемого байта таблицы. Поэтому ка- ждый байт таблицы, смещение которого относительно начала таблицы соответствует допустимому значению исходного сим- вола, должен содержать код определенного символа. Этот код и помещается вместо исходного символа в поле результата. Команда MOVTC использует первые шесть регистров и по- мещает в них следующее: в R0 — число подлежащих перекоди- рованию символов, оставшихся в исходной строке (это число
446 Глава 15 равно нулю, если длина исходной строки не превышает длину поля, предоставляемого для результата); в R1— адрес первого байта, следующего за последним перекодированным байтом ис- ходной строки; в R2 и R4 — нули, в R3 — адрес таблицы пере- кодировки, в R5 — адрес первого байта, располженного в ре- зультирующей строке за последним байтом, помещенным в эту строку. Для определения условия завершения операции следует про- верить значения битов N и Z признака результата. Биту N присваивается значение 1, если длина исходной строки оказа- лась меньше длины строки результата, биту Z присваивается значение 1 при совпадении длин двух строк. Другая команда перекодирования символов — команда MOVTUC (MOVE TRANSLATED (UNTIL) CHARACTER — ПЕ- РЕСЫЛКА С ПЕРЕКОДИРОВАНИЕМ ДО ПОЯВЛЕНИЯ СИМВОЛА). Команды MOVTC и MOVTUC выполняются оди- наково, однако символ-заполнитель не используется, и операция может завершиться при возникновении одной дополнительной ситуации. Если команда MOVTC завершает перекодирование символов только при исчерпании символов исходной строки или отсутствии места для размещения символов этой строки, то команда MOVTUC, кроме того, может завершиться при обна- ружении в таблице перекодировки особого символа. Команда MOVTUC имеет следующий обобщенный формат: MOVTUC длина_исходной_строки, адрес_исходной_строки, символ-ограничитель, длина_поля^размещения_ результата, адрес _по ля _ размещения ^результата Чтобы можно было определить условие завершения выпол- нения команды MOVTUC (обнаружение символа-ограничителя либо достижение конца исходной строки или поля ее размеще- ния), команда MOVTUC присваивает биту V значение 1, если встретился символ-рграничитель, и значение 0—в противопо- ложном случае. Кроме того, биту N присваивается значение 1, если длина исходной строки меньше длины результирующей строки, а биту Z — значение 1, если длины обеих строк равны. Команда MOVTUC использует первые шесть регистров и помещает в них следующее: в R0 — число символов, оставшихся в исходной строке необработанными, включая символ, который вызвал преждевременное завершение операции, если оно про- изошло (R0 содержит нуль, если символ-ограничитель не встре- тился и результирующая строка по длине не меньше исходной); в R1—адрес байта исходной строки, который обрабатывался в момент завершения операции (если завершение произошло в результате обнаружения символа ограничителя, то в R1 поме-
Остальные команды системы VAX 447 щается адрес символа, вызвавшего это; если завершение про- изошло по достижении конца результирующей строки, то в R1 помещается адрес последнего перекодированного символа ис- ходной строки; если завершение произошло по достижении кон- ца исходной строки, то в R1 помещается адрес первого байта, следующего за исходной строкой), в R2 — нуль; в R3 — адрес таблицы перекодировки; в R4 — число байт, оставшихся неза- полненными в результирующей строке (это число равно нулю, если результирующая строка заполнена до конца); в R5—ад- рес первого незаполненного байта поля для результирующей строки (если операция не завершается преждевременно, этот адрес является адресом первого байта, следующего за резуль- тирующей строкой). 15.6. Команда EDITPC Программы на языке Кобол содержат большое число операций редактирования, которые реализуются операторами пересылки данных. При выполнении подобных операций над десятичными упакованными данными осуществляется подавление ведущих нулей, включение в строку упакованных десятичных цифр зна- ка и размещение символа доллара слева от старшего знача- щего разряда. Команда EDITPC (EDIT PACKED ТО CHARAC- TER — РЕДАКТИРОВАНИЕ УПАКОВАННОГО ЧИСЛА) имеет следующий обобщенный формат: EDITPC длина„исходной„строки, адрес_исходной„строки, шаблон, адрес „размещения „результата Первые два операнда определяют упакованное десятичное число. Операнд шаблон задает адрес подлежащей выполнению функции (или функций) редактирования. Последний операнд является адресом местоположения результирующей строки сим- волов, представляемой в коде ASCII. Шаблон редактирования задается с помощью одного или нескольких операторов, некоторые из которых имеют операнды, подлежащие заданию. Эти операнды используются для указа- ния длины строки или значения символа-заполнителя. В каче- стве операторов шаблона редактирования применяются опера- торы вставки, перемещения, фиксирования местоположения и загрузки символов, а также передачи управления. Последова- тельность операторов шаблона редактирования завершается специальным оператором EO$END. Полное описание команды EDITPC приведено в справочни- ке фирмы DEC по архитектуре системы VAX-1L
448 Глава 15 15.7. Блокировка доступа к памяти Архитектура системы VAX обеспечивает полезную возможность коллективного использования модифицируемых данных. Для этого программа сначала должна получить полный контроль над совместно используемыми данными и затем сохранять его до завершения операции. В системе VAX такая возможность называется блокировкой доступа. Предусмотрено семь команд, которые во время выполнения блокируют доступ к различным структурам данных. Здесь приводится лишь краткий обзор этих команд, полное их описание содержится в справочнике по ар« хитектуре системы VAX. Две команды, блокирующие доступ, используются для пере- дачи управления по условию и модификации значений битов. Команды BBSSI (BRANCH ON BIT SET AND SET INTER- LOCKED — ПЕРЕХОД ЕСЛИ БИТ РАВЕН 1, ПРИСВОЕНИЕ БИТУ ЗНАЧЕНИЯ 1 С БЛОКИРОВКОЙ) и BBCCI (BRANCH ON BIT CLEAR AND CLEAR INTERLOCKED — ПЕРЕХОД, ЕСЛИ БИТ РАВЕН О, ПРИСВОЕНИЕ БИТУ ЗНАЧЕНИЯ О с БЛОКИРОВКОЙ)—аналогичны командам BBSS и ВВСС со- ответственно. Единственное различие между этими двумя па- рами команд заключается в том, что команды BBSSI и BBCCI во время выполнения блокируют другим процессорам или устройствам доступ к байту, содержащему модифицируемый бит. Команда ADAWI (ADD ALIGNED WORD INTERLOCKED- СЛОЖЕНИЕ ВЫРОВНЕННЫХ СЛОВ С БЛОКИРОВКОЙ) является двухадресной командой сложения содержимого слов и подобна команде ADDW2. Однако в отличие от последней команда ADAWI требует, чтобы слова, которые являются опе- рандами, были выровнены на границу слова (т. е. имели бы четные адреса), и блокирует доступ к этим словам на время выполнения другим процессорам и устройствам. Четыре команды с блокировкой доступа оперируют с очере- дями. Очереди, обрабатываемые этими командами, несколько отличаются от очередей, рассмотренных в разд. 15.1. Вместо действительных адресов элементов (хранящихся в указателях FLINK и BLINK) в этих очередях используются смещения адре- сов, размещаемые в полях размером длинное слово. К этим командам относятся INSQHI (INSERT INTO QUEUE AT HEAD, INTERLOCKED —ДОБАВЛЕНИЕ ЭЛЕМЕНТА В НА- ЧАЛО ОЧЕРЕДИ С БЛОКИРОВКОЙ), INSQTI (INSERT INTO QUEUE AT TAIL, INTERLOCKED — ДОБАВЛЕНИЕ ЭЛЕМЕНТА В КОНЕЦ ОЧЕРЕДИ С БЛОКИРОВКОЙ), REMQH1 (REMOVE FROM QUEUE AT HEAD, INTER- LOCKED — УДАЛЕНИЕ ЭЛЕМЕНТА ИЗ НАЧАЛА ОЧЕРЕДИ С БЛОКИРОВКОЙ) и REMQTI (REMOVE FROM QUEUE AT.
Остальные команды системы VAX 449 TAIL, INTERLOCKED —УДАЛЕНИЕ ЭЛЕМЕНТА ИЗ КОНЦА ОЧЕРЕДИ С БЛОКИРОВАНИЕМ). Отметим, что по своему действию эти команды аналогичны уже рассмотренным команд дам работы с очередями. Основные их отличия заключаются в следующем: добавление элементов к очередям и удаление эле* ментов из очередей производится только из начала или конца очереди, вместо действительных адресов элементов используют- ся смещения, очереди на время выполнения команд блокируют- ся. Эти четыре команды, как и рассмотренные выше в этой главе команды работы с очередями, не могут быть прерваны во время выполнения. 15.8. Дополнительные команды системы VAX В этом разделе кратко рассматриваются дополнительные команды системы VAX. Некоторые из них относятся к катего- рии привилегированных команд, т. е. не могут применяться в обычном режиме выполнения системой VAX программы поль- зователя. Первые несколько команд (из числа перечисляемых ниже), однако, доступны обычным пользователям системы VAX. Впрочем, применяются они сравнительно редко. 15.8.1. Команды, доступные пользователям Когда в программе требуется указать способ представления константы, перед ней следует разместить символы S~ или 1~, соответствующие так называемым литеральному и непосред- ственному представлениям. Напомним, что поскольку операнды типа литерал хранятся в байте кода режима адресации, они должны быть очень малы по величине. Значения целых чисел должны находиться в диапазоне 0—63. Числа с плавающей точ- кой должны быть малы по диапазону возможных значений и точности представления, допустимые границы этих значений приводятся в руководстве по программированию на языке ас- семблера системы VAX-П. Преимущество литерального пред- ставления перед непосредственным заключается в значительно более экономном расходе памяти. Разумеется, для известного значения константы транслятор всегда сам выбирает форму ее представления, минимизирующую объем используемой памяти. Поэтому единственным случаем, требующим от пользователя задания формы представления константы, является ситуация, когда значение константы неизвестно, и при этом предпола- гается, что приемлемым является литеральное представление. Команда JMP предназначена для безусловной передачи управления к любому адресуемому полю виртуального адрес- ного пространства системы VAX. Операнд этой команды может быть задан с использованием любого режима адресации, вклю- 15 Зак. 483
450 Глава 15 чая косвенную адресацию и индексирование. Когда используется относительная адресация «смещением к СК» и известно значе- ние операнда, транслятор выбирает самое маленькое допусти- мое значение смещения. Кроме случаев использования косвен- ной или индексной адресации, необходимость в команде JMP. возникает редко. Команда JSB аналогична команде JMP. Действительно, форматы их операндов совпадают. Однако JSB является коман- дой вызова подпрограммы, как команды BSBW и BSBB. Ис- пользование команды JSB целесообразно только при необходи- мости применения косвенной или индексной адресации. Команда NOP(NO OPERATION — НЕТ ОПЕРАЦИИ) не выполняет никаких действий, но занимает место в памяти (1 байт) и использует время процессора (1 цикл). Команда MOVPSL (MOVE PSL — ПЕРЕСЫЛКА СЛОВА СОСТОЯНИЯ ПРОЦЕССОРА) помещает текущее значение слова состояния процессора (PSL) в адресуемое операндом поле размером длинное слово. Команды BICPSW и BISPSW позволяют присваивать зна- чение 0 или 1 содержимому отдельных разрядов или их ком- бинациям в той половине PSL, которая доступна пользователю, а именно разрядам слова состояния программы (PSW). Эти команды действуют аналогично командам BICW2 и BISW2 со- ответственно. Каждая команда имеет только один операнд — маску длиной 16 бит, задаваемую на языке ассемблера в виде последовательности битов, следующих за символами "М. При выполнении команды BISPSW над содержимым PSW и значе- нием маски производится операция ИЛИ. При выполнении команды BICPSW сначала вычисляется дополнение значения маски, а затем под этим дополнением и содержимым PSW про- изводится операция И. Эти команды часто используются для изменения значения битов PSW, управляющих различными ви- дами прерываний. Например, следующая команда присваивает значение 1 биту, управляющему прерыванием типа «перепол- нение целого»: BISPSW #~M<IV) Команда CRC (CYCLIC REDUNDANCY CHECK —ЦИКЛИ- ЧЕСКАЯ ПРОВЕРКА НА ИЗБЫТОЧНОСТЬ) предоставляет довольно «экзотическую» возможность для проверки достовер- ности строки символов, передаваемых системами связи. С по- мощью многочисленных арифметических операций значения те- стовой последовательности вычисляются как некоторый полином до и после передачи данных, а затем сравниваются. Если эти два значения не совпадают, в ходе передачи имели место иска- жения,
Остальные команды системы VAX 451 Команда ВРТ (BREAK POINT FAULT —ПРЕРЫВАНИЕ В КОНТРОЛЬНОЙ ТОЧКЕ) позволит реализовать в системе VAX работу некоторых средств отладки. Эта команда не имеет опе- рандов и просто вызывает прерывание выполнения программы в контрольной точке с сохранением в стеке содержимого PSL. Команды EMODF и EMODD производят операции умноже- ния с увеличением размера дробной части множителя на 8 бит, что обеспечивает расширение поля (а следовательно, и точно- сти представления) мантиссы дробной части результата до 32 или 64 бит соответственно. Эти команды имеют следующий обобщенный формат: КОП множитель, расширение-множителя, множимое, целая-часть-результата, дробная-часть-результата Тип данных, используемых в качестве множимого, множителя и дробной части результата, определяется кодом операции. Длина поля представления операнда расширение-множителя равна 1 байт. Поскольку значение содержимого этого поля обычно неизвестно, в это поле записывается 0. Целая часть ре- зультата размещается в поле размером длинное слово. Выпол- нение этих команд состоит из следующих последовательных шагов: 1) расширение дробной части множителя путем добавления к ней содержимого разрядов байта, задаваемого как значение операнда расширение-множителя-, 2) умножение множимого на расширенный множитель (дробная часть результата выполнения команды EMODF со- держит 32 бита, а команды EMODD — 64 бита); 3) запись целой части результата в поле, адресуемое одно- именным операндом (целая-часть-результата); 4) запись округленного значения дробной части результата в поле, адресуемое одноименным операндом (дробная-часть- результата). Эти команды используются прежде всего для повышения точности вычислений, например в «стандартных» подпрограм- мах вычисления тригонометрических функций, обращения к ко- торым содержат такие языки программирования, как Фортран. В набор команд системы VAX входит группа команд услов- ной передачи управления, несколько отличающихся от широко используемых в тексте этой книги. Эти команды называются неарифметическими, поскольку они размещаются в программе вслед за командами, не выполняющими арифметические опера- ции и, следовательно, не воздействующими на бит-индикатор признака результата операции. Такими командами являются, на- пример, команды обработки строк битов или строк символов, 15*
452 Глава 15 команды сравнения адресов. В эту группу входят команды BLLSU, BLEQU, BLEQLU, BNEQU, BGEQU, BGTRU. В при. веденной ниже таблице показано, при каких условиях (значе- ниях битов признака результата выполнения предыдущей коман- ды) эти команды выполняют передачу управления: Код операции Значения битов — индикаторов признака результата BLSSU BLEQU BEQLU BNEQU BGEQU BGTRU II О N || S N S S3 — —' —' О о о II II II II II II О О N N О О Отметим, что команды BEQLU и BNEQU эквивалентны ко- мандам BEQL и BNEQ соответственно. Это объясняется тем, что содержимое разряда знака не влияет на результат выполнения этих команд. Остальные четыре команды, однако, проверяют значение бита переноса (бита С), а не бита-индикатора отрица- тельного значения результата (бита N). Эти команды предна- значены для условной передачи управления по результату вы- полнения команды, оперирующей целыми числами без знака. Неарифметические команды условной передачи управления, как и все остальные команды условной передачи управления систе- мы VAX, используют смещение размером байт. Для выявления различия между неарифметическими коман- дами условной передачи управления и соответствующими им обычными (арифметическими) командами, рассмотрим следую- щую команду: СМРВ #~Х80, #~X7F В результате выполнения этой команды биту N признака ре- зультата присваивается значение 1. Первый операнд — число отрицательное, так как левый бит двоичного кода значения этого операнда имеет значение 1, второй операнд — число положитель- ное. Результат вычитания шестнадцатеричных чисел 7F и 80 —> отрицательное число. Однако после выполнения операции вычи- тания биту переноса признака результата присваивается значе- ние 0, потому что значение 1 присваивается этому биту только в том случае, когда первый операнд меньше второго и оба опе- ранда рассматриваются как не имеющие знака. Шестнадцате-
Остальные команды системы VAX 453 ричная величина 80, интерпретируемая как число без знака, ра- зумеется, не меньше, чем интерпретируемая аналогичным обра- зом величина 7F. Поэтому после такой операции сравнения команда BLSSU не выполнит условной передачи управления, а команда BLSS — выполнит. Отметим также различие в формировании значения бита С признака результата командами сравнения и арифметическими командами. При выполнении арифметических команд биту С присваивается значение 1, если возникает перенос из самого старшего разряда числа (а не из разряда знака). При выполне- нии команд сравнения происходит то же самое, но старшим раз- рядом в этом случае является самый левый разряд, так как опе- ранды рассматриваются как числа без знака. Команды типа CHMx (CHANGE MODE — ИЗМЕНЕНИЕ РЕЖИМА), используются для изменения режима работы про- цессора системы VAX. Команда СНМЕ устанавливает режим выполнения, команда СНМК — режим ядра, команда CHMS — режим супервизора, команда CHMU — режим пользователя. Эти команды применяются при обращении программ пользователей с запросами к операционной системе на выполнения определен- ных сервисных процедур. 15.8.2. Привилегированные команды Все рассматриваемые ниже команды являются привилегирован- ными. Они зарезервированы для получения данных о состоянии системы и для использования в системном программном обеспе- чении. Команды MFPR (MOVE FROM PRIVILEGED REGISTER — ИЗВЛЕЧЕНИЕ СОДЕРЖИМОГО ПРИВИЛЕГИРОВАННОГО РЕГИСТРА) и MTPR (MOVE ТО PRIVILEGED REGISTER — ЗАПИСЬ В ПРИВИЛЕГИРОВАННЫЙ РЕГИСТР) обеспечи- вают доступ к 30 привилегированным регистрам системы VAX. В этих регистрах хранятся идентифицирующая систему инфор- мация, указатель стека прерываний и т. п. Команды LDPCTX (LOAD PROCESS CONTEXT — ЗАГРУЗ- КА КОНТЕКСТА ПРОЦЕССА) и SVPCTX (SAVE PROCESS CONTEXT — СОХРАНЕНИЕ КОНТЕКСТА ПРОЦЕССА) ис- пользуются для восстановления и сохранения информации о со- стоянии регистров и памяти в системе. Вся эта информация за- поминается и восстанавливается из области памяти, называемой блоком управления процессом. Команды типа PROBEx используются для определения до- ступности заданного поля (операнда команды) для чтения (команда PROBER) или для записи (команда PROBEW). Эти команды используются операционной системой VMS в тех слу- чаях, когда выполнение некоторой команды задерживается до
454 Глава 15 тех пор, пока VMS не определит возможность завершения вы- полнения без прерываний при соблюдении установленного режи- ма доступа к одному из операндов. Команда REI (RETURN FROM EXCEPTION OR INTER- RUPT — ВОЗВРАТ ИЗ ПРОЦЕДУРЫ ОБРАБОТКИ ОСОБОЙ СИТУАЦИИ ИЛИ ПРЕРЫВАНИЯ) предназначена для возвра- та из процедуры, которая выполняет обработку некоторых си- туаций, связанных с обнаружением ошибок и прерываний си- стемы VAX. Команда XFC (EXTENDED FUNCTION CALL—ВЫЗОВ СРЕДСТВ РАСШИРЕНИЯ НАБОРА КОМАНД) предназначена для расширения набора команд системы VAX, если это нужно какой-либо группе пользователей для решения особых задач. Новые команды реализуются в виде нестандартных микропро- грамм или процедур программного обеспечения. Команда HALT не имеет операндов. В результате ее выпол- нения работа центрального процессора останавливается. Код опе- рации команды HALT на машинном языке представляется в виде нуля, и поэтому если в программе, выполняемой в режиме пользователя, ошибочно предпринимается попытка передать управление полю данных с нулевым содержимым, возникнет ошибка «привилегированная команда» (или, точнее, попытка вы- полнения привилегированной команды). Итак, рассмотрены или хотя бы упомянуты все команды из стандартного набора команд системы VAX. Выводы 1. Очереди в системе VAX представляют собой двунаправ- ленные списки. Команды INSQUE и REMQUE выполняют соот- ветственно добавление элементов в очередь и удаление элемен- тов из очереди. 2. Локальные метки используются для ссылок в пределах сравнительно небольшого участка программы. 3. Команды типа CASE* являются средством многоальтерна- тивного выбора передачи управления. Смещение адресов, кото- рые в программе следуют за командами CASEx, позволяют по- лучить адрес, по которому передается управление. 4. Арифметические операции целочисленной арифметики по- вышенной точности реализуются командами ADWC и SBWC. 5. Команды MOVTC и MOVTUC обеспечивают возможность преобразования представления строки символов из одного кода в другой. Команда MOVTC выполняет перекодирование и пере- сылку заданного количества символов, а команда MOVTUC вы- полняет те же действия до тех пор, пока среди перекодирован- ных символов не появится специальный символ,
Остальные команды системы VAX 455 6. Команда EDITPC выполняет операцию редактирования десятичных упакованных чисел, и используется при трансляции программ, написанных на языке Кобол. 7. Команды с блокированием доступа к памяти используются в системных программах для управления коллективно исполь- зуемыми структурами данных. 8. Для задания константы возможны два способа ее пред- ставления: непосредственное представление, указанием перед ней символов ~1, и литеральное, указанием символов "S. 9. Команды JMP и JSB используются в тех случаях, когда удобно применять индексную или косвенную адресацию для за- дания адреса перехода к подпрограмме. 10. Команды условной передачи управления используются после неарифметических команд, выполняющих операции над данными без знака для проверки значения бита С признака ре- зультата, но не бита N. 11. В системе VAX предусмотрена группа привилегирован- ных команд, в число которых входят команды доступа к приви- легированным регистрам и изменения режима работы процес- сора. Новые команды ADWC BLSSU CHMU JMP PROBER BBCCI BNEQU CRC JSB PROBEW BBSSI BPT EDITPC LDPCTX REI BEQLU CASEB EMODD MFPR REMQHI BGEQU CASEL EMODF MOVPSL REMQTI BGTRU CASEW HALT MOVTC REMQUE BICPSW CHM.E INSQHI MOVTUC SBWC BISPSW CHMK INSQTI MTPR SVPCTX BLEQU CHMS INSQUE NOP XFC Новые термины Блокировка доступа Блок локальных меток Извлечь из очереди Конец очереди Начало очереди Поставить в очередь Вопросы и упражнения 1. Куда добавляются новые элементы: в начало или в ко- нец очереди? 2. Опишите структуру заголовка очереди в системе VAX. 3. Для чего очереди в системе VAX нужен заголовок?
456 Глава 15 4. Опишите все операции,. выполняемые командой REMQUE. 5. Опишите все операции, выполняемые командой INS.QUE. 6. В чем различие между командами CASEB и CASEL? 7. Если в команде типа CASEx второй и третий операнды имеют значения соответственно 7 и 12, то сколько допустимых значений и какие именно может принимать переключатель? 8. Постройте конструкцию многоальтернативного выбора передачи управления, эквивалентную следующей конструкции на языке Паскаль: CASE SELECT OF BEGIN 3: WRITELN ('сумма = ', VALUE2); 4: BEGIN INDEX :== INDEX + 1; WRITELN ('сумма = ', VALUE3) END; 5: WRITELN ('сумма = , VALUES) OTHERWISE WRITELN ('ОШИБКА, ПЕРЕКЛЮЧАТЕЛЬ =', SELECT) END 9. Укажите все различия между командами ADDL2 и ADWC. 10. Составьте таблицу перекодирования десятичных цифр, представленных в коде ASCII, в символ «звездочка» в коде ASCII, а всех букв верхнего регистра, представленных в коде ASCII, — в буквы нижнего регистра в этом же коде. Таблица предназначена для использования в команде MOVTC. Никакие другие символы, кроме указанных, изменяться не должны. 11. Каково содержимое регистров R4 и R5 после выполнения команды MOVTUC? 12. Каково назначение команды CRC? 13. В чем различие между шестью неарифметическими ко- мандами условной передачи управления и соответствующими им командами, которые ставятся после арифметических операций?
Приложение А Эмулятор вычислительной машины TOYCOM Эмулятор машины TOYCOM — это программа на языке програм- мирования высокого уровня, заставляющая ЭВМ, на которой эта программа выполняется, функционировать точно так же, как и машина TOYCOM. Указанная программа состоит из двух ча- стей: транслятора языка ассемблера машины TOYCOM (извест- ного под названием TOYCODE) и интерпретатора машинного языка TOYCOM. Магнитную ленту с записанной на ней програм- мой «Эмулятор TOYCOM» можно получить у автора книги или любого представителя фирмы Benjamin/Cummings. Чтобы осуществить пуск эмулятора, на клавиатуре терми- нала нужно набрать команду RUN TOYCOM. В ответ эмулятор выдает сообщение в виде вопроса: NEW (НОВЫЙ)? или OLD (СТАРЫЙ)? Пользователь должен указать, желает ли он рабо- тать с новой программой или старой, записанной на магнитном диске. После ответа пользователя (NEW или OLD) эмулятор запрашивает имя файла, т. е. имя программы, с которой пользо- ватель желает работать. Если требуется режим работы OLD, т. е. работа с уже существующей программой, пользователю не- обходимо ввести имя, присвоенное содержащему эту программу файлу ранее, при ее создании в режиме NEW. Если требуется работа в режиме NEW, т. е. необходимо формирование новой программы, пользователь должен присвоить файлу имя, содер- жащее не более пяти символов и начинающееся с буквы. После ввода пользователем имени файла эмулятор выдает сообщение «NEXT (СЛЕДУЮЩЕЕ)?», означающее готовность принимать от пользователя следующие команды. По команде LIST выполняется трансляция программы на языке TOYCODE и выдается соответствующий листинг. По команде RUN эмулятор TOYCOM транслирует и выпол- няет указанную программу. При вводе команды RUN могут быть одновременно заданы некоторые дополнительные ключевые сло- ва, уточняющие режим работы. Ключевое слово LIST явля- ется требованием вывода текста программы перед ее выполне- нием. Ключевое слово TRACE обеспечивает вывод значений со- держимого счетчика команд (СК) и аккумулятора (АК) для каждой команды выполняемой программы (трассировку выпол-
458 Приложения нения). Так осуществляется трассировка выполнения программы, существенно облегчающая поиск ошибок. Кроме того, это дает на- глядное общее представление о выполнении программ TOYCOM. По ключевому слову DUMP выводится содержимое памяти ма- шины (дамп) на момент завершения выполнения программы. Это позволяет проконтролировать машинные команды, фактиче- ски реализующие выполнение текущей программы. Упомянутый дамп содержит также таблицу символических имен, используе- мых в данной программе. Для каждого символического имени указывается адрес области памяти, присвоенный ему во время трансляции. Указанный дамп включает копию содержимого только тех частей памяти, которые заняты программой и отно- сящимися к ней данными. Команда SAVE позволяет записать текущую программу на магнитный диск. Программа будет храниться в форме файла с тем именем, которое было введено при ответе на вопрос TOYCOM об имени файла после выбора пользователем режима работы NEW. При необходимости замены устаревшей версии программы ее обновленным вариантом следует воспользоваться командой REPLACE. Отметим, что команды OLD и NEW могут использоваться в ответ на любой очередной вопрос машины «NEXT»?, а не только в начале работы с ней. Но в то же время подача (ввод) коман- ды OLD, вызвающей чтение существующей программы из вто- ричной (внешней) памяти, всегда приводит к уничтожению те- кущей программы. По команде EXIT управление передается обратно операцион- ной системе. Добавление, исключение и замена отдельных команд в про- грамме на языке TOYCODE могут быть легко выполнены, если команды программы снабжены соответствующими номерами. В качестве номера можно использовать любое целое (не более 32767) число без знака, размещаемое перед командой в строке, ей предназначенной. Машина TOYCOM автоматически упорядочивает команды программы на языке TOYCODE в соответствии с их номерами. Поэтому добавление новой команды в любое место программы может быть легко выполнено, если номер этой команды «укла- дывается» в последовательность номеров того места программы, где данная команда размещена. Например, если требуется вста- вить новую команду между командами программы, имеющими номера 20 и 30, достаточно ее ввести с любым порядковым но- мером, большим 20 и меньшим 30 (допустим, с номером 25). Эта новая команда будет размещена между командами с порядко- выми номерами 20 и 30. При формировании первоначальной вер-
Приложения 459 сии программы желательно вести нумерацию команд с достаточ- но большим шагом. Это позволит в дальнейшем при необходи- мости вводить в программу большое число дополнительных команд. Любую команду можно легко удалить из текста программы, для чего достаточно на клавиатуре терминала набрать только ее номер без какого-либо дополнительного текста. Замена команды производится набором порядкового номера заменяемой команды вместе с заменяющим ее новым текстом. Отметим, что все изменения в программах должны выпол- няться только указанным выше образом. Для редактирования исходных текстов нельзя использовать типовые редакторы тек- стов, такие, как ТЕСО или EDT.
Приложение Б Таблица преобразования десятичных чисел в шестнадцатеричные и обратно Номера разрядов шестнадцатеричного числа 8 7 6 5 4 3 2 1 0 0 0 0 0 0 0 0 0 1 268435456 16777216 1048576 65536 4096 256 16 1 2 536870912 33554432 2097152 131072 8192 512 32 2 3 805306368 50331648 3145728 196608 12288 768 48 3 4 1073741824 67108864 4194304 262144 16348 1024 64 4 5 1342177280 83886080 5242880 327680 20480 1280 80 5 6 1610612736 100663296 6291456 393216 24576 1593 96 6 7 1879048192 117440512 7340032 458752 28672 1792 112 7 8 2147483648 134217728 8388608 524288 32768 2048 128 8 9 2415919104 150994944 9437184 589824 36864 2304 144 9 А 2684354560 167772160 10485760 655360 40960 2560 160 10 В 2952790016 184549376 11534336 720896 45056 2816 176 11 С 3221225472 201326592 12582912 786432 49152 3072 192 12 D 3489660928 218103808 13631488 851968 53248 3328 208 13 Е 3758096384 234881024 14680064 917504 57344 3584 224 14 F 4026531840 251658240 15728640 983040 61440 3840 240 15
Приложение В Код ASCII1» 16-римЫй эквивалент 10-ричный' эквивалент ASCII 16-ричный эквивалент 10-ричный эквивалент ASCII 16-ричный эквивалент 10-ричный эквивалент ASCII 16-ричный эквивалент 10-ричный эквивалент ASCII 00 0 NUL 20 32 SP 40 64 @ 60 ’ 96 i 01 1 SOH 21 33 ! 41 65 А 61 97 а 02 2 STX 22 34 н 42 66 В 62 98 b 03 3 ETX 23 35 # 43 67 С 63 99 с 04 4 EOT 24 36 $ 44 68 D 64 100 d 05 5 ENQ 25 37 % 45 69 £ 65 101 а Об 6 ACK 26 38 & 46 70 F 66 102 £ 07 7 BEL 27 39 t 47 71 G 67 103 8 08 8 BS 28 40 1 48 72 И 68 104 h 09 9 HT 29 41 ) 49 73 I 69 105 i 0А 10- LF 2A 42 * 4A 74 J 6А 106 J QB И vr 2B 43 + 4B 75 К 6В 107 k ОС .12 FF 2C 44 / 4C 76 L 6С 108 1 0D 13 CR ' 2D 45 4D 77 М 6D 109 m ОЕ 14 SO 2E 46 4E 78 N 6Е 110 n OF 15 SI 2F 47 / 4F 79 О 6F 111 0 10 16 DLE 30 48 0 50 80 Р 70 112 P 11 17 DC1 31 49 1 51 81 Q 71 ИЗ <1 12 18 DC2 32 50 2 52 82 R 72 114 i 13 19 DC3 33 51 3 53 83 S 73 115 8 14 20 DC4 34 52 4 54 84 Т 74 116 t 15 21 NAK 35 53 5 55 85 и 75 117 u 16 22 SYN 36 54 6 56 86 V ’76 118 V 17 23 ETB 37 55 7 57 87 W 77 119 w 18 24 CAN 38 56 8 58 88 X 78 120 X 19 25 EM 39 57 9 59 89 Y 79 121 У 1А 26 SUB ЗА 58 • 5A 90 Z 7А 122 z 1В 27 ESC ЗВ 59 J 5B 91 1 7В 123 { 1С 23 FS ЗС 60 < 5C 92 7С 124 1 ID 29 GS 3D 61 t3 5D 93 ] 7D 125 } IE 30 RS ЗЕ 62 > 5E 94 Л 7Е 126 IF 31 US 3F 63 1 5F 95 м 7F 127 DEL ° Стандартный восьмибитовый код, применяемый в системах обработки информации для представления данных. — Прим. ред.
Приложение Г Макрокоманды ввода-вывода и стандартные подпрограммы МАКРОКОМАНДЫ ; НАБОР МАКРООПРЕДЕЛЕНИЙ ВВОДА И ВЫВОДА : ДЛЯ ПРОГРАММ НА ЯЗЫКЕ АССЕМБЛЕРА СИСТЕМЫ VAX .TITLE ЮМАС .IDENT /IO_MACROS/ • МАКРООПРЕДЕЛЕНИЕ INIT_IO ; ПОДГОТОВКА К ВЫПОЛНЕНИЮ ОПЕРАЦИЙ ОБМЕНА ; С ТЕРМИНАЛОМ .MACRO INIT-IO BRW ARND.. ALIGN LONG ; ФОРМИРОВАНИЕ БЛОКОВ RAB И FAB ДЛЯ ВВОДА ;И ВЫВОДА IN.FAB: $FAB FAC = GET, FNM==(SYS$INPUT) IN.RAB:: $RAB FAB== IN. FAB OUT.FAB: $FAB FAC = PUT, FNM==<SYS$OUTPUT) OUT.RAB:: $RAB FAB = OUT. FAB OUT.BUF:: .BLKB 132 ; БУФЕР ВЫВОДА IN.BUF:: .BLKB 80 ; БУФЕР ВВОДА CR.LF:: .BYTE 13,10 ; КОДЫ ASCII ДЛЯ ; СИМВОЛОВ «ВОЗВРАТ КАРЕТКИ» И ;«ПЕРЕВОД СТРОКИ» Q..:: .BYTE 63 ; КОД ASCII ДЛЯ СИМВОЛА ; «ВОПРОСИТЕЛЬНЫЙ ЗНАК» ; ОТКРЫТИЕ ФАЙЛОВ И УСТАНОВЛЕНИЕ СВЯЗИ МЕЖДУ ; RAB И FAB ARND..:: $OPEN FAB = IN.FAB $OPEN FAB = OUT.FAB ; ЕСЛИ ОШИБКА ПРИ ОТКРЫТИИ, ТО ВЫВОД
Приложения 463 ; СООБЩЕНИЯ ОБ ОШИБКЕ И ОСТАНОВ BLBS R0, 20$ PRINT-L ОШИБКА ПРИ ОТКРЫТИИ ФАЙЛА В МАКРОКОМАНДЕ INIT.IO' $EXIT_S • КОНЕЦ ОПЕРАЦИЙ «ЕСЛИ» 20$: $CONNECT RAB = IN.RAB $CONNECT RAB = OUT.RAB ; ЕСЛИ ОШИБКА ПРИ УСТАНОВЛЕНИИ СВЯЗИ, ТО ВЫВОД ; СООБЩЕНИЯ ОБ ОШИБКЕ И ОСТАНОВ BLBS R0, 30$ PRINT.L ‘“ОШИБКА ПРИ УСТАНОВЛЕНИИ СВЯЗИ В МАКРОКОМАНДЕ INIT.IO' $EXIT_S ; КОНЕЦ ОПЕРАЦИЙ «ЕСЛИ» 30$: .ENDM * ♦♦$*****$**$****$**$*$*$$$$*$*$$***$**$$******:!!*?' ; МАКРООПРЕДЕЛЕНИЕ PRINT.L ; ВЫВОД НА ТЕРМИНАЛ ЗНАЧЕНИЙ ЦЕЛЫХ ЧИСЕЛ . РАЗМЕРОМ ДЛИННОЕ СЛОВО •MACRO PRINT.L LABEL, VI, V2, V3, V4, V5, V6,?- LAB, ?ARND •NARG COUNT ... ; ЦИКЛ ЗАГРУЗКИ В СТЕК ВСЕХ ; ЗАДАННЫХ АРГУМЕНТОВ МАКРОКОМАНДЫ .IRP ARG, (V6, V5, V4, V3, V2, VI) .IIF NOT.BLANK, ARG, PUSHL ARG •ENDR ; ВЫЗОВ PRTL ПО CALL PUSHAB LAB PUSHL #<%LENGTH (LABEL))
Bl Приложения PUSHL CALLS BRB LAB: .ASCII ARND: .ENDM #(COUNT ... - 1) # (COUNT ... +2), PRTL ARND «LABEL® 1 МАКРООПРЕДЕЛЕНИЕ PRINT_B i ВЫ ВОД НА ТЕРМИНАЛ ЗНАЧЕНИЙ ЦЕЛЫХ ЧИСЕЛ РАЗМЕРОМ БАЙТ .MACRO PRINT_B LABEL, VI, V2, V3, V4, V5, V6/ ?LAB, ?TEMP, ?ARND .NARG COUNT ... I ЦИКЛ ЗАГРУЗКИ В СТЕК ВСЕХ J ЗАДАННЫХ АРГУМЕНТОВ МАКРОКОМАНДЫ * * * .IRP ARG, (V6, V5, V4, V3, V2, VI) .IIF NOT.BLANK, ARG, CVTBL ARG,- TEMP .IIF NOT-BLANK, ARG, PUSHL TEMP .ENDR $ | ВЫЗОВ PRTL ПО CALL PUSHAB LAB PUSHL #(% LENGTH (LABEL)) PUSHL # (COUNT ... - 1) CALLS # (COUNT ... +2), PRTL BRB ARND LAB: .ASCII @LABEL@ TEMP: .BLKL 1 ARND: .ENDM ♦ * ♦ I ; МАКРООПРЕДЕЛЕНИЕ PRINT_W ; ВЫВОД НА ТЕРМИНАЛ ЗНАЧЕНИЙ ЦЕЛЫХ ЧИСЕЛ ; РАЗМЕРОМ СЛОВО .MACRO PRINT.W LABEL, VI, V2, V3, V4, V5,- V6, ?LAB, ?TEMP, ?ARND .NARG COUNT ... 9
Приложения 465 ; ЦИКЛ ЗАГРУЗКИ В СТЕК ВСЕХ ; ЗАДАННЫХ АРГУМЕНТОВ МАКРОКОМАНДЫ .IRP ARG, (V6, V5, V4, V3, V2, VI) .IIF NOT .BLANK, ARG, CVTWL ARG, TEMP .IIF NOT-BLANK, ARG, PUSHL TEMP .ENDR » ; ВЫЗОВ PRTL ПО CALL PUSHAB LAB PUSHL #(%LENGTH (LABEL)) PUSHL # (COUNT ... - 1) CALLS # (COUNT ... +2), PRTL BRB ARND LAB: .ASCII @LABEL@ TEMP: .BLKL 1 ARND: .ENDM {**«*$ф**|||********1|1**ф**ф1|1**$*1|1***||>1|1*||>$*******«*** ; МАКРООПРЕДЕЛЕНИЕ READ-L ; ВВОД С ТЕРМИНАЛА ЗНАЧЕНИИ ЦЕЛЫХ ЧИСЕЛ ; РАЗМЕРОМ ДЛИННОЕ СЛОВО .MACRO READ-L VI, V2, V3, V4, V5, V6 .NARG COUNT ... ; ЦИКЛ ЗАГРУЗКИ В СТЕК ВСЕХ ; ЗАДАННЫХ АРГУМЕНТОВ МАКРОКОМАНДЫ .IRP ARG, (V6, V5, V4, V3, V2, VI) .IIF NOT-BLANK, ARG, PUSHAL ARG •ENDR ВЫЗОВ REDL ПО CALL PUSHL #3 PUSHL # COUNT... CALLS # (COUNT ... + 2), REDL .ENDM ; ...I,*******...**.*.*.***.*..*..*.*.. ............. ; МАКРООПРЕДЕЛЕНИЕ READ-W ; ВВОД С ТЕРМИНАЛА ЗНАЧЕНИИ ЦЕЛЫХ ЧИСЕЛ ; РАЗМЕРОМ СЛОВО
466 Приложения .MACRO READ-W VI, V2, V3, V4, V5, V6 .NARG COUNT... ЦИКЛ ЗАГРУЗКИ В СТЕК ВСЕХ ЗАДАННЫХ АРГУМЕНТОВ МАКРОКОМАНДЫ .IRP ARG, (V6, V5, V4, V3, V2, VI) .IIF NOT-BLANK, ARG, PUSHAW ARG .ENDR ; ВЫЗОВ PRTL ПО CALL PUSHL #2 PUSHL # COUNT... CALLS # (COUNT ... + 2), REDL .ENDM » ; МАКРООПРЕДЕЛЕНИЕ READ-B ; ВВОД С ТЕРМИНАЛА ЗНАЧЕНИЙ ЦЕЛЫХ ЧИСЕЛ ; РАЗМЕРОМ БАЙТ .MACRO READ-B VI, V2, V3, V4, V5, V6 .NARG COUNT ... ЗАГРУЗКА В СТЕК ВСЕХ ЗАДАННЫХ АРГУМЕНТОВ МАКРОКОМАНДЫ JRP ARG, (V6, V5, V4, V3, V2, VI) .IIF NOT-BLANK, ARG, PUSHAB ARG .ENDR ; ВЫЗОВ REDL ПО CALL PUSHL #1 PUSHL # COUNT... CALLS # (COUNT ... + 2), REDL .ENDM • ********************* ♦*********>!<********>|<М**!1<*** ; МАКРООПРЕДЕЛЕНИЕ READ.A ;ВВОД С ТЕРМИНАЛА СТРОКИ СИМВОЛОВ ; В КОДЕ ASCII .MACRO READ-A STR-ADDR PUSHAB STR-ADDR
Приложения 467 .CALLS # 1, REDA .ENDM $ ********************************************** * * * ; МАКРООПРЕДЕЛЕНИЕ PRINT-A ; ВЫВОД НА ТЕРМИНАЛ СТРОКИ СИМВОЛОВ ; В КОДЕ ASCII .MACRO PRINT-A LABEL, LENGTH, STR-ADDR,?- LAB, ? TEMP,? ARND PUSHL # (% LENGTH(LABEL) > PUSHAB LAB MOVZWL LENGTH, - (SP) PUSHAB STR-ADDR CALLS #4, PRTA BRB ARND LAB: ASCII ©LABEL® ARND: .ENDM ************************************************** ; МАКРООПРЕДЕЛЕНИЕ DUMP ; ФОРМИРОВАНИЕ ДАМПА СОДЕРЖИМОГО ; ЗАДАННОГО УЧАСТКА ПАМЯТИ И ; РЕГИСТРОВ .MACRO DUMP START, END PUSHAL END PUSHAL START CALLS #2, DUMPER .ENDM .END ПОДПРОГРАММЫ ; НАБОР ПОДПРОГРАММ ОПЕРАЦИЙ ВВОДА-ВЫВОДА ; ДЛЯ ПРОГРАММ НА ЯЗЫКЕ АССЕМБЛЕРА СИСТЕМЫ VAX .TITLE IOSUB .SUBTITLE PROCEDURE PRTL--PRINT INTEGERS .IDENT /10- SUBPROGRAMS/ • ПРОЦЕДУРА PRTL ; ВЫВОДИТ НА ТЕРМИНАЛ ЗНАЧЕНИЯ ЦЕЛЫХ ЧИСЕЛ ; РАЗМЕРОМ ДЛИННОЕ СЛОВО ; ПАРАМЕТРЫ: ; 1) КОЛИЧЕСТВО ВЫВОДИМЫХ ЧИСЕЛ ; 2) ДЛИНА ВЫВОДИМОЙ ЛИТЕРАЛЬНОЙ МЕТКИ ; 3) АДРЕС ЛИТЕРАЛЬНОЙ МЕТКИ
468 Приложения ;4) -? ВЫВОДИМЫЕ ЧИСЛА ; ОШИБКИ: ТОЛЬКО ОШИБКИ ВВОДА-ВЫВОДА .ENTRY PRTL, "M(R2, R3, R4, R5, R6, R7, R8> NUM.VALS =4 LEN_LIT=8 ADDR_LIT = 12 VALS = 16 ; ОЧИСТКА БУФЕРА MOVC5 # 0, OUT.BUF, # ~А/ /, # 132, OUT.BUF •, ПЕРЕСЫЛКА СТРОКИ В БУФЕР ВЫВОДА MOVC3 LEN_LIT(AP), eADDR-LIT(AP), OUT.BUF ; ЗАГРУЗКА В R6 АДРЕСА ПЕРВОГО ЧИСЛА, А В R7 АДРЕСА ;БУФЕРА 1 ADDL3 # 16, АР, R6 MOVAB OUT.BUF, R7 ADDL2 LEN_LIT(AP), R7 INCL R7 i ЦИКЛ ПРЕОБРАЗОВАНИЯ ЧИСЕЛ С ПОСЛЕДУЮЩИМ ВЫВОДОМ ; ДЛЯ KOUNT := NUM_VALS(AP) С ШАГОМ -1 ; ДО 1 ВЫПОЛНЯТЬ В ЦИКЛЕ MOVL NUM-VALS(AP), KOUNT CMPL KOUNT, # 1 BGEQ CVT_LOOP BRW OUT_CVT CVT_LOOP: ; ПРЕОБРАЗОВАНИЕ ОЧЕРЕДНОГО ЧИСЛА В СТРОКУ ; УПАКОВАННЫХ ДЕСЯТИЧНЫХ ЦИФР, А ЗАТЕМ В ЧИСЛОВУЮ ; СТРОКУ с РАЗДЕЛЬНЫМ ВЕДУЩИМ ЗНАКОМ CVTLP (R6), # 10, TEMP-BUF CVTPS # 10, TEMP_BUF, # 11, (R7) • СМЕЩЕНИЕ УКАЗАТЕЛЕЙ ВНИЗ ADDL2 # 14, R7 ADDL2 #4, R6 ACBL # 1, # - 1, KOUNT, CVT-LOOP
Приложения 469 ; КОНЕЦ ЦИКЛА «ДЛЯ» ; ЗАГРУЗКА В R7 ДЛИНЫ ЗАПОЛНЕННОЙ ; ЧАСТИ БУФЕРА OUT-CVT; MOVAB OUT.BUF, R8 SUBL2 R8, R7 ; ВЫВОД НА ТЕРМИНАЛ ДАННЫХ И ; СИМВОЛОВ «ВОЗВРАТ КАРЕТКИ» И «ПЕРЕВОД СТРОКИ» $RAB_STORE RAB == OUT.RAB, RBF «OUT.BUF, RSZ = R7 $PUT RAB = OUT.RAB ; ЕСЛИ ОШИБКА ПРИ ВЫВОДЕ ДАННЫХ, ТО ; ВЫВОД СООБЩЕНИЯ ОБ ; ОШИБКЕ И ОСТАНОВ BLBS R0, 10$ PRINT-A #27, P_PUT_MESS $EXIT_S ; КОНЕЦ ОПЕРАЦИЙ «ЕСЛИ» 10$: $RAB_STORE RAB = OUT.RAB, RBF = CR.LF, RSZ == #2 $PUT RAB = OUT.RAB RET ; ОБЛАСТЬ ПАМЯТИ ДЛЯ ПЕРЕМЕННЫХ, ; ИСПОЛЬЗУЕМЫХ В ПРОЦЕДУРЕ PRTL P_PUT_MESS: .ASCII 'ОШИБКА ПРИ ВЫВОДЕ ДАННЫХ' TEMP-BUF; .BLKB 6 ; РАБОЧАЯ ОБЛАСТЬ ; ДЛЯ ПРЕОБРАЗОВАНИЙ KOUNT: .BLKL 1 ; СЧЕТЧИК ЦИКЛА .PAGE .SUBTITLE PROCEDURE REDL-----READ INTEGERS > ; J************************************************************************* ; ПРОЦЕДУРА REDL ; ВВОДИТ С ТЕРМИНАЛА ЦЕЛЫЕ ЧИСЛА В ВИДЕ СОЧЕТАНИИ ; СИМВОЛОВ ЦИФР КОДА ASCII, ПРЕОБРАЗУЕТ ; ИХ В ЦЕЛЫЕ ЧИСЛА РАЗМЕРОМ БАЙТ, СЛОВО ИЛИ ; ДЛИННОЕ СЛОВО ; ПАРАМЕТРЫ: ; 1) КОЛИЧЕСТВО ВВОДИМЫХ ЧИСЕЛ
470 Приложения ; 2) КОД РАЗМЕРА ЧИСЛА: ; (1 - БАЙТ, 2 - СЛОВО, 3 - ДЛИННОЕ СЛОВО) ; 3-? АДРЕСА, ПОЛЕЙ, В КОТОРЫХ ДОЛЖНЫ БЫТЬ ; РАЗМЕЩЕНЫ ЗНАЧЕНИЯ ВВОДИМЫХ ЧИСЕЛ ОШИБКИ: ЕСЛИ ВВОДИМОЕ ЧИСЛО ПРЕВЫШАЕТ УСТАНОВЛЕННОЕ МАКСИМАЛЬНОЕ ЗНАЧЕНИЕ, ТО ВЫВОДИТСЯ СООБЩЕНИЕ ОБ ОШИБКЕ И ВЫПОЛНЕНИЕ ПРОЦЕДУРЫ ПРЕРЫВАЕТСЯ ; ПРИМЕЧАНИЕ: ЕСЛИ КОЛИЧЕСТВО ВВОДИМЫХ ЧИСЕЛ МЕНЬШЕ УКАЗАННОГО, ТО СОДЕРЖИМОМУ ПОЛЕЙ, ОСТАВШИХСЯ НЕЗАПОЛНЕННЫМИ, ПРИСВАИВАЮТСЯ НУЛЕВЫЕ ЗНАЧЕНИЯ .ENTRY REDL, ~М <R2, R3, R4, R5, R6, R7, R8, R9, R10> • ЗАГРУЗКА В R7 ЧИСЛА АДРЕСНЫХ ПАРАМЕТРОВ, ; В R4 И R5- АДРЕСА СПИСКА АДРЕСОВ ; И В ОБЛАСТЬ SIZE —КОДА РАЗМЕРА ЧИСЕЛ MOVL 4(АР), R7 ADDL3 #8, АР, R4 MOVL (R4) +, SIZE MOVL R4, R5 ; ПРИСВОЕНИЕ ВСЕМ ПАРАМЕТРАМ НУЛЕВЫХ ЗНАЧЕНИЙ ; ДЛЯ COUNT := 1 С ШАГОМ 1 ДО R7 ; ВЫПОЛНЯТЬ В ЦИКЛЕ MOVL # 1, COUNT CMPL COUNT, R7 BLEQ ZERO-LOOP BRW OUT-LOOP ZERO-LOOP: • ЕСЛИ SIZE = 1, TO CMPL SIZE, #1 BNEQ ELSE-l ; ОЧИСТКА БАЙТА CLRB @(R5) + BRW ENDIF-1 ; ИНАЧЕ ЕСЛИ SIZE = 2, TO
Приложения 471 ELSE-l: CMPL SIZE, #2 BNEQ ELSE-2, ; ОЧИСТКА СЛОВА CLRW @(R5) 4- BRW ENDIF-2 ; ИНАЧЕ ОЧИСТКА ДЛИННОГО СЛОВА ELSE-2: CLRL @(R5) + ; КОНЕЦ ОПЕРАЦИИ «ЕСЛИ» ; КОНЕЦ ОПЕРАЦИИ «ЕСЛИ» ENDIF-2: ENDIF-1: AOBLEQ R7, COUNT, ZERO-LOOP ; КОНЕЦ ЦИКЛА «ДЛЯ» ; ВВОД СТРОКИ СИМВОЛОВ OUT-LOOP: $RAB_STORE RAB = OUT.RAB, RBF = CR.LF, RSZ=#2 $PUT RAB = OUT.RAB $RAB_STORE RAB = OUT.RAB, RBF = Q RSZ = #1 $PUT RAB = OUT.RAB ; ЕСЛИ ОШИБКА ПРИ ВЫВОДЕ ДАННЫХ, ТО ; ВЫВОД СООБЩЕНИЯ ОБ ОШИБКЕ И ОСТАНОВ BLBS R0, 20$ PRINT-A #27, R-PUT-MESS $EXIT_S ; КОНЕЦ ОПЕРАЦИИ «ЕСЛИ» 20$: $RAB_STORE RAB = IN.RAB, UBF = IN.BUF, USZ = #80 $GET RAB = IN.RAB ; ЕСЛИ ОШИБКА ПРИ ЧТЕНИИ, ТО ; ВЫВОД СООБЩЕНИЯ ОБ ОШИБКЕ И ОСТАНОВ } BLBS R0, 30$
472 Приложения PRINT-A #27, R_GET_MESS $EXIT_S КОНЕЦ ОПЕРАЦИИ «ЕСЛИ» [ ЗАГРУЗКА В R8 ДЛИНЫ ВВЕДЕННОЙ ПОСЛЕДОВАТЕЛЬНОСТИ ; СИМВОЛОВ И ДОБАВЛЕНИЕ СИМВОЛА ПРОБЕЛА ; К КОНЦУ ПОСЛЕДОВАТЕЛЬНОСТИ 30$: MOVAB IN.BUF, R9 MOVZWL IN.RAB + RAB$W_RSZ, R8 ADDL3 R9, R8, R10 MOVB #32, (R10) INCL R8 • ЗАМЕНА ВСЕХ ЗАПЯТЫХ ПРОБЕЛАМИ ; ОТЫСКАНИЕ ПЕРВОГО ПРОБЕЛА MOVL R8, R6 LOCC # ~А/,/, R6, IN.BUF ; ПОКА ИМЕЮТСЯ ЗАПЯТЫЕ И НЕОБРАБОТАННЫЕ СИМВОЛЫ ; ВО ВХОДНОЙ ПОСЛЕДОВАТЕЛЬНОСТИ, ВЫПОЛНЯТЬ В ЦИКЛЕ COMMA-LOOP: TSTL R0 BEQL NO_MORE_COMMAS TSTL R6 BLEQ NO_MORE_COMMAS ; ЗАМЕНА ЗАПЯТОЙ ПРОБЕЛОМ MOVL Rl, RIO MOVB #лА/ /, (RIO) INCL RIO MOVL RO, R6 DECL R6 ; ОТЫСКАНИЕ СЛЕДУЮЩЕЙ ЗАПЯТОЙ LOCC # ^А/,/, R6, (R10) BRW COMMA-LOOP ; КОНЕЦ ЦИКЛА «ПОКА» NO-MORE-COMMAS:
Приложения 473 ; ДЛЯ COUNT := 1 С ШАГОМ 1 ДО R7 ; ВЫПОЛНЯТЬ В ЦИКЛЕ MOVL # 1, COUNT CMPL COUNT, R7 BLEQ MAIN_ LOOP BRW OUT MAIN-LOOP: • ОТЫСКАНИЕ НАЧАЛА ПЕРВОГО ЧИСЛА - ПЕРВОГО ; СИМВОЛА, НЕ ЯВЛЯЮЩЕГОСЯ ПРОБЕЛОМ SKPC # ~А/ /, R8, (R9) TSTL R0 BNEQ ARND BRW OUT ARND: MOVL RO, R8 MOVL Rl, R9 ; В ДАННЫЙ МОМЕНТ СОДЕРЖИМОЕ R9 РАВНО ; АДРЕСУ СЛЕДУЮЩЕГО ЧИСЛА ; ДАЛЕЕ ВЫПОЛНЯЕТСЯ ПОИСК ПЕРВОГО ОГРАНИЧИТЕЛЯ ;ЧИСЛА LOCC # "AZ /, R8, (R9) ; ЕСЛИ ЧИСЛО БЕЗ ЗНАКА СМРВ #"AZ-Z, (R9) BEQL HAS-SIGN СМРВ # "AZ+Z, (R9) BEQL HAS-SIGN ; ЗАМЕНА ОГРАНИЧИТЕЛЯ ПРОБЕЛОМ DECL R9 INCL R8 MOVB # "AZ Z. (R9) КОНЕЦ ОПЕРАЦИЙ <ЕСЛИ» HAS-SIGN: ; ЗАГРУЗКА ДЛИНЫ ЧИСЛА (БЕЗ УЧЕТА
474 Приложения ; ЗНАКА) В R10 SUBL3 RO, R8, R10 DECL R10 ; ПРЕОБРАЗОВАНИЕ ЧИСЛА В ДВОИЧНУЮ ФОРМУ CVTSP RIO, (R9), # 12, BUF CVTPL # 12, BUF, TEMP ; ЕСЛИ ПЕРЕПОЛНЕНИЕ, ТО BVC OK ; ВЫВОД СООБЩЕНИЯ И ВЫХОД ИЗ ПРОЦЕДУРЫ PRINT-L ХЧ'***ОШИБКА — ВХОДНАЯ ВЕЛИЧИНА СЛИШКОМ ВЕЛИКА' RET ; КОНЕЦ ОПЕРАЦИЙ «ЕСЛИ» ОК: j ЕСЛИ SIZE = 1, ТО CMPL SIZE, # 1 BNEQ ELSE1 РАЗМЕЩЕНИЕ ПРЕОБРАЗОВАННОГО ЧИСЛА В ПОЛЕ РАЗМЕРОМ БАЙТ CVTLB TEMP, @(R4)+ BRW ENDIF 1 I ; ИНАЧЕ ЕСЛИ SIZE =2, TO ELSE1: CMPL SIZE, #2 BNEQ ELSE2 ; РАЗМЕЩЕНИЕ ПРЕОБРАЗОВАННОГО ЧИСЛА ; В ПОЛЕ РАЗМЕРОМ СЛОВО CVTLW TEMP, @(R4)+ BRW ENDIF2
Проложения 475 ; ИНАЧЕ-ПЕРЕСЫЛКА ЧИСЛА В ПОЛЕ ; РАЗМЕРОМ ДЛИННОЕ СЛОВО ELSE2: MOVL TEMP, @(R4) + КОНЕЦ ОПЕРАЦИЙ «ЕСЛИ» ; КОНЕЦ ОПЕРАЦИЙ «ЕСЛИ» ENDIF2: ENDIF1; ; ЕСЛИ ПЕРЕПОЛНЕНИЕ, ТО BVC NOT-TOO-BIG ; ВЫВОД СООБЩЕНИЯ ОБ ОШИБКЕ ; И ВЫХОД ИЗ ПРОЦЕДУРЫ PRINT-L -""ОШИБКА - ВХОДНАЯ ВЕЛИЧИНА СЛИШКОМ ВЕЛИКА' RET ; КОНЕЦ ОПЕРАЦИЙ «ЕСЛИ» NOT-TOO-BIG: ; ИЗМЕНЕНИЕ СОДЕРЖИМОГО РЕГИСТРОВ R9 (ТЕКУЩИЙ ; УКАЗАТЕЛЬ СИМВОЛА ВО ВХОДНОЙ ПОСЛЕДОВАТЕЛЬНОСТИ) ; И R8 (ДЛИНА ОСТАВШЕЙСЯ ЧАСТИ ПОСЛЕДОВАТЕЛЬНОСТИ) ADDL2 RIO, R9 ADDL2 # 2, R9 SUBL2 RIO, R8 SUBL2 #2, R8 ACBL R7, # 1, COUNT, MAIN-LOOP КОНЕЦ ЦИКЛА «ДЛЯ» OUT: RET ; ОБЛАСТЬ ПАМЯТИ ДЛЯ ПЕРЕМЕННЫХ, ; ИСПОЛЬЗУЕМ! IX В ГРОЦЕДУРЕ REDL R-PUT-MESS: .ASCII ""ОШИБКА ПРИ ВЫПОЛНЕНИИ ВЫВОДА В ПРОЦЕССЕ ЧТЕНИЯ'
476 Приложения R_GET_MESS: .ASCII '***ОШИБКА ПРИ ВЫПОЛНЕНИИ ВВОДА BUF: .BLKB В ПРОЦЕССЕ ЧТЕНИЯ' 12 s РАБОЧАЯ ОБЛАСТЬ ДЛЯ ПРЕОБРАЗОВАНИЯ ; ЧИСЕЛ COUNT: .BLKL 1 ; СЧЕТЧИК ДЛЯ ОБОИХ ЦИКЛОВ ПЕРЕБОРА ; СИМВОЛОВ ВХОДНОЙ TEMP: .BLKL ; ПОСЛЕДОВАТЕЛЬНОСТИ 1 ; ОБЛАСТЬ ПАМЯТИ ДЛЯ ВРЕМЕННОГО SIZE: .BLKL ; ХРАНЕНИЯ ЗНАЧЕНИЯ ЧИСЛА 1 ; ОБЛАСТЬ ПАМЯТИ ДЛЯ ХРАНЕНИЯ КОДА ; РАЗМЕРА ЧИСЕЛ .PAGE .SUBTITLE PROCEDURE REDA-------READS CHARACTER STRINGS 5 • *************^*******^**^*********************^*******^****^^************ ; ПРОЦЕДУРА REDA ; ВЫПОЛНЯЕТ ВВОД СТРОКИ СИМВОЛОВ В ; КОДЕ ASCII В ПАМЯТЬ ПАРАМЕТРЫ:; ; 1) АДРЕС ОБЛАСТИ ПАМЯТИ, НАЧИНАЯ С КОТОРОГО ДОЛЖНА БЫТЬ РАЗМЕЩЕНА ПОСЛЕДОВАТЕЛЬНОСТЬ СИМВОЛОВ I .ENTRY REDA, <R2, R3, R4, R5) STR_ADDR=4 ; ВВОД СТРОКИ СИМВОЛОВ С ТЕРМИНАЛА $RAB_STORE RAB = OUT.RAB, RBF = CR.LF.RSZ = # 2 $PUT RAB = OUT.RAB ; ЕСЛИ ОШИБКА ПРИ ВЫПОЛНЕНИИ ВЫВОДА ДАННЫХ, ТО ; ВЫВОД СООБЩЕНИЯ ОБ ОШИБКЕ И ОСТАНОВ BLBS RO, 10$ PRINT_A #27, R_PUT_MESS $EXIT_S • КОНЕЦ ОПЕРАЦИИ «ЕСЛИ» 10$: $RAB_STORE RAB = OUT.RAB, RBF = Q.., RSZ=#1 $PUT RAB = OUT.RAB j ЕСЛИ ОШИБКА ПРИ ВЫПОЛНЕНИИ ВЫВОДА, ТО . ВЫВОД СООБЩЕНИЯ ОБ ОШИБКЕ И ОСТАНОВ
Приложения 477 BLBS RO, 20$ PRINT-A #27, R_PUT_MESS $EXIT_S • КОНЕЦ ОПЕРАЦИИ «ЕСЛИ» 20$: $RAB_STORE RAB = IN.RAB, UBF = IN.BUF, USZ=#80 $GET RAB = IN.RAB ; ЕСЛИ ОШИБКА при выполнении ввода, то ; ВЫВОД СООБЩЕНИЯ ОБ ОШИБКЕ И ОСТАНОВ BLBS R0, 30$ PRINT-A #27, R-GET-MESS $EXIT_S ; КОНЕЦ ОПЕРАЦИИ «ЕСЛИ» 30$: MOVC3 IN.RAB + RAB$W_RSZ, IN.BUF, @STR_ADDR (АР) RET .PAGE .SUBTITLE PROCEDURE PRTA---PRINT CHARACTER STRINGS ; ПРОЦЕДУРА PRTA : ВЫВОД СТРОКИ СИМВОЛОВ В КОДЕ ASCII • ПАРАМЕТРЫ: 1) АДРЕС НАЧАЛА СТРОКИ 2) ДЛИНА СТРОКИ 3) АДРЕС ЛИТЕРАЛЬНОЙ МЕТКИ ; 4) ДЛИНА ЛИТЕРАЛЬНОЙ МЕТКИ] .ENTRY PRTA, ~M(R2, R3, R4, R5, R7> STR_ADDR = 4 LEN_STR = 8 ADDR_LIT = 12 LEN_LIT= 16 ♦ ; ОЧИСТКА БУФЕРА MOVC5 #0, OUT.BUF, #~А/ /, # 132, OUT.BUF ПЕРЕСЫЛКА ЛИТЕРАЛЬНОЙ МЕТКИ В БУФЕР ВЫВОДА
478 Приложения M0VC3 LEN-LIT (АР), @ADDR_LIT (АР), OUT.BUF ; ИЗМЕНЕНИЕ СОДЕРЖИМОГО РЕГИСТРА R7 (УКАЗАТЕЛЯ ; БУФЕРА) НА АДРЕС СТРОКИ 1 MOVAB OUT.BUF, R7 ADDL2 LEN-LIT (АР), R7 INCL R7 ; ПЕРЕСЫЛКА СТРОКИ В БУФЕР M0VC3 LEN-STR (АР), @STR_ADDR (АР), (R7) ADDL3 LEN_STR (АР), LEN_LIT (АР), R7 INCL R7 ; ВЫВОД СОДЕРЖИМОГО БУФЕРА НА ТЕРМИНАЛ $RAB_STORE RAB = OUT.RAB, RBF = OUT.BUF, RSZ = R7 $PUT RAB = OUT.RAB ; ЕСЛИ ОШИБКА ПРИ ВЫПОЛНЕНИИ ВЫВОДА ДАННЫХ, ТО ; ВЫВОД СООБЩЕНИЯ ОБ ОШИБКЕ И ОСТАНОВ BLBS R0, 10$ PRINT.L '’'•"ОШИБКА ПРИ ЗАПИСИ В МАКРОКОМАНДЕ PRINT-A' $EXIT_S ; КОНЕЦ ОПЕРАЦИИ «ЕСЛИ» 10$: $RAB_STORE RAB = OUT.RAB, RBF = CR.LF, RSZ=#2 $PUT RAB = OUT.RAB RET .PAGE .SUBTITLE PROCEDURE DUMPER---DUMP REGISTERS & MEMORY > * *:£****? $***$***$****$$$:£*:£*:£ од# ффффф од ффДОфОДффффффОДВДфОДфОДфДО од* ; ПРОЦЕДУРА DUMPER ; ФОРМИРУЕТ ШЕСТНАДЦАТЕРИЧНЫЙ ДАМП ; СОДЕРЖИМОГО РЕГИСТРОВ И ОБЛАСТИ ПАМЯТИ ; ПАРАМЕТРЫ: ; 1) НАЧАЛЬНЫЙ АДРЕС ОБЛАСТИ ПАМЯТИ ; 2) КОНЕЧНЫЙ АДРЕС ОБЛАСТИ ПАМЯТИ ’ .ENTRY DUMPER, <R2, R3, R4, R5, R7> MOVL 4(AP), START
Приложения 479 MOVL 8 (АР), END ВЫВОД СОДЕРЖИМОГО ПЕРВЫХ ВОСЬМИ РЕГИСТРОВ MOVQ RO, VALUE-BUF MOVQ R2, VALUE-BUF + 8 MOVQ R4, VALUE-BUF + 16 MOVQ R6, VALUE-BUF + 24 MOVZBW LABEL1, LEN PRINT-A LEN, LABEL 1 + 1 $RAB_STORE RAB = OUT.RAB, RBF = CR.LF, RSZ=#2 $PUT RAB = OUT.RAB MOVZBW LABEL2, LEN PRINT-A LEN, LABEL2 + 1 PUSHL #8 CALLS #1, PRINT-BUF ВЫВОД СОДЕРЖИМОГО ПОСЛЕДНИХ ВОСЬМИ РЕГИСТРОВ MOVQ R8, VALUE-BUF MOVQ RIO, VALUE-BUF + 8 MOVQ 8(FP), VALUE-BUF + 16 MOVL #0, VALUE-BUF + 24 MOVL 16 (FP), VALUE-BUF + 28 MOVZBW LABEL3, LEN PRINT-A LEN, LABEL3 + 1 PUSHL #8 CALLS # 1, PRINT-BUF ЦИКЛ ВЫВОДА ДАМПА ПАМЯТИ $RAB_STORE RAB = OUT.RAB, RBF = CR.LF, RSZ = #2 $PUT RAB = OUT.RAB MOVZBW LABEL4, LEN PRINT-A LEN, LABEL4+1 ПРЕОБРАЗОВАНИЕ НАЧАЛЬНОГО АДРЕСА ОБЛАСТИ ПАМЯТИ (ШЕСТНАДЦАТЕРИЧНОЕ ПРЕДСТАВЛЕНИЕ) В КОД ASCII И ВЫВОД MOVC5 # О, LABEL7 + 37, # "А/ /, # 10, LABEL7 + 37 MOVL #38, R7 ДЛЯ DIGIT :=7 С ШАГОМ -1 ДО 0 ВЫПОЛНЯТЬ В ЦИКЛЕ
480 Приложения MOVL #7, DIGIT CONV-LOOP: ПРЕОБРАЗОВАТЬ СОДЕРЖИМОЕ ПОЛУБАЙТА В СИМВОЛ ШЕСТНАДЦАТЕРИЧНОЙ ЦИФРЫ В КОДЕ ASCII MULL3 #4, DIGIT, R8 EXTZV R8, #4, START, R9 ПЕРЕСЫЛКА БАЙТА С СИМВОЛОМ ШЕСТНАДЦАТЕРИЧНОЙ ЦИФРЫ В КОДЕ ASCII В БУФЕР ВЫВОДА MOVB HEX-ASCII [R9], LABEL7 [R7] INCL R7 ACBL #0, #-l, DIGIT, CONV-LOOP КОНЕЦ ЦИКЛА ; OUT-CONV-LOOP: ; ВЫВОД НАЧАЛЬНОГО АДРЕСА ; ОБЛАСТИ ПАМЯТИ MOVZBW LABEL7, LEN PRINT-A LEN, LABEL7+ 1 $RAB_STORE RAB = OUT.RAB, RBF = CR.LF, RSZ = # 2 $PUT RAB = OUT.RAB MOVZBW LABELS, LEN PRINT-A LEN, LABELS + 1 ; ПЕРЕУСТАНОВКА ГРАНИЧНЫХ АДРЕСОВ ДЛЯ ; ДАМПА ПАМЯТИ НА ЗНАЧЕНИЯ, КРАТНЫЕ 4 BICL2 #~Х2, START BICL2 # ~Х2, END ; ADDL2 #4, END ; ПРИСВОЕНИЕ ПЕРЕМЕННОЙ LENGTH ;ЗНАЧЕНИЯ КОЛИЧЕСТВА СТРОК ДАМПА ’ SUBL3 START, END, LENGTH ASHL #-5, LENGTH, LENGTH ; ЕСЛИ LENGTH < 0, TO TSTL LENGTH BGEQ IT _IS _OK ; ПРИСВОЕНИЕ ПЕРЕМЕННОЙ LENGTH НУЛЕВОГО ЗНАЧЕНИЯ CLRL LENGTH
Приложения 481 ; КОНЕЦ ОПЕРАЦИИ «ЕСЛИ» IT-IS.OK; ; ДЛЯ LINE-COUNTER = О С ШАГОМ 1 ДО LENGTH ; ВЫПОЛНЯТЬ В ЦИКЛЕ CLRL LINE-COUNTER CMPL LINE-COUNTER, LENGTH BLEQ LINE-LOOP BRW OUT_LINE_LOOP LINE-LOOP: ; ПЕРЕСЫЛКА В БУФЕР СОДЕРЖИМОГО ВОСЬМИ ДЛИННЫХ ; СЛОВ И ВЫВОД MOVC3 #32, ©START, VALUE-BUF+4 MOVL START, VALUE_BUF PUSHL #9 CALLS * #1, PRINT-BUF ADDL2 #32, START AOBLEQ LENGTH, LINE-COUNTER, LINE-LOOP ; КОНЕЦ ЦИКЛА «ДЛЯ» OUT_LINE_LOOP: $RABSTORE RAB = OUT.RAB, RBF = CR.LG, RSZ = #2 $PUT RAB = OUT.RAB MOVZBW LABEL6, LEN PRINT_A LEN, LABEL6 + 1 RET ; ПРОЦЕДУРА PRINT-BUF ; ВЫВОДИТ СОДЕРЖИМОЕ ВОСЬМИ ; ДЛИННЫХ СЛОВ ПАМЯТИ В ВИДЕ СИМВОЛОВ ; 16-РИЧНЫХ ЦИФР В КОДЕ ASCII ; ПАРАМЕТР: ; ФЛАГ-ИНДИКАТОР РАСПОЛОЖЕНИЯ ДАННЫХ (О ОБОЗНАЧАЕТ, ЧТО 8 ДЛИННЫХ СЛОВ ПАМЯТИ РАСПОЛОЖЕНЫ В РЕГИСТРАХ; 1 - В ОПЕРАТИВНОЙ ПАМЯТИ) .ENTRY PRINT-BUF, ~M(R2, R3, R4, R5, R7, R8, R9> MOVL 4 (AP), NUM-VALUES MOVC5 #0, OUT.BUF, # ~A/ /, #80, OUT.BUF MOVAB OUT.BUF, OUT_PTR MOVAL VALUE_BUF, VALUE.PTR • ЕСЛИ ЗНАЧЕНИЕ ПАРАМЕТРА РАВНО 9, ТО V216 Зак 483
482 Приложения CMPL NUM_VALUES, #9 BNEQ EIGHT • ПРИСВОЕНИЕ СЧЕТЧИКУ ЧИСЛА ВЫВОДИМЫХ СТРОК ;ЗНАЧЕНИЯ 9 ADDL2 # 72, OUT-PTR BRB ENDIF7 ; ИНАЧЕ ПРИСВОЕНИЕ СЧЕТЧИКУ ВЫВОДИМЫХ СТРОК ;ЗНАЧЕНИЯ 8 EIGHT: ADDL2 #63, OUT-PTR ; КОНЕЦ ОПЕРАЦИЙ «ЕСЛИ» ENDIF7: ; ЦИКЛ ПРЕОБРАЗОВАНИЯ ДАННЫХ (ВЫПОЛНЯЕТСЯ ; 8 ИЛИ 9 ПРОХОДОВ ОПЕРАТОРОВ ТЕЛА ЦИКЛА) ; ДЛЯ REG := О С ШАГОМ 1 ДО NUM.VALUES ; ВЫПОЛНЯТЬ В ЦИКЛЕ CLRL R7 CMPL R7, NUM-VALUES BLEQ VALUE-LOOP BRW OUT_VALUE_LOOP VALUE-LOOP; ПРЕОБРАЗОВАНИЕ ЧИСЛА ИЗ ДВОИЧНОГО КОДА • В 16-РИЧНОЕ ПРЕДСТАВЛЕНИЕ В КОДЕ ASCII ; ДЛЯ DIGIT := 7 С ШАГОМ -1 ДО О ; ВЫПОЛНЯТЬ В ЦИКЛЕ MOVL # 7, DIGIT DIGIT-LOOP: ; ПРЕОБРАЗОВАНИЕ ПОЛУБАЙТА ; В СИМВОЛ ШЕСТНАДЦАТЕРИЧНОЙ ЦИФРЫ В КОДЕ ASCII MULL3 #4, DIGIT, R8 EXTZV R8, #4, ®VALUE_PTR, R9 ; ПЕРЕСЫЛКА ШЕСТНАДЦАТЕРИЧНОЙ ЦИФРЫ
Приложения 483 ; В БУФЕР ВЫВОДА И СМЕНА ЗНАЧЕНИЯ MOVB HEX-ASCII [R9], @OUT_PTR INCL OUT-PTR SOBGEQ DIGIT, DIGIT-LOOP ; КОНЕЦ ЦИКЛА «ДЛЯ» (ПАРАМЕТР ЦИКЛА DIGIT) ; ИЗМЕНЕНИЕ ЗНАЧЕНИЯ OUT_PTR ДЛЯ ФОРМИРОВАНИЯ ; ПРОБЕЛОВ МЕЖДУ ОТДЕЛЬНЫМИ ЧИСЛАМИ ; SUBL2 #17, OUT.PTR ADDL2 #4, VALUE-PTR ACBL NUM-VALUES, #1, R7, VALUE-LOOP * • КОНЕЦ ЦИКЛА «ДЛЯ» (ПАРАМЕТР REG) OUT_VALUE_LOOP; $RAB_STORE RAB=OUT.RAB, RBF=OUT.BUF, RSZ = #8O $PUT RAB=OUT.RAB ; ЕСЛИ ОШИБКА ПРИ ВЫВОДЕ ДАННЫХ, ТО ; ВЫВОД СООБЩЕНИЯ ОБ ОШИБКЕ И ОСТАНОВ BLBS RO, 10$ PRINT. А # 24, D.PUT.MESS $EXIT_S J ; КОНЕЦ ОПЕРАЦИЙ «ЕСЛИ» 10$: $RAB_STORE RAB = OUT.RAB, RBF = CR.LF, RSZ = #2 $PUT RAB = OUT.RAB RET ; ОБЛАСТЬ ПАМЯТИ ДЛЯ ПЕРЕМЕННЫХ, ; ИСПОЛЬЗУЕМЫХ В ПРОЦЕДУРАХ DUMPER И PRINT.BUF LABEL1: .ASCIC ' ****** ДАМП СОДЕРЖИМОГО РЕГИСТРОВ *»***' LABEL2: .ASCIC — 'R7 R6 R5 R4 R3 R2 Rl R0z LABEL: .ASCIC - PC SP FP AP Rll RIO R9 R8' LABEL4: .ASCIC ' ***** ДАМП СОДЕРЖИМОГО ПАМЯТИ ***♦♦' LABELS: .ASCIC — —СОДЕРЖИМОЕ— АДРЕС' ’A 16*
484 Приложения LABEL6: .ASCIC ' ********** КОНЕЦ ДАМПА **********' LABEL7: .ASCIC r НАЧАЛЬНЫЙ АДРЕС:' LEN: .BLKW 1 ; ДЛИНА МЕТОК D_PUT_MESS: .ASCII 'ОШИБКА ПРИ ВЫВОДЕ ДАННЫХ ; В ПРОЦЕДУРЕ ДАМПА' HEX-ASCII: .ASCII '0123456789ABCDEF'; ТАБЛИЦА ; ПРЕОБРАЗОВАНИЙ DIGIT: .BLKL 1 ; СЧЕТЧИК ЦИФР START: .BLKL 1 ; НАЧАЛЬНЫЙ АДРЕС ОБЛАСТИ ; ПАМЯТИ END: .BLKL 1 : КОНЕЧНЫЙ АДРЕС ; ОБЛАСТИ ПАМЯТИ LENGTH: .BLKL 1 ; ЧИСЛО СТРОК В ДАМПЕ VALUE_BUF: .BLKL 9 ; БУФЕР ДЛЯ ВЫВОДИМЫХ ;ЗНАЧЕНИЙ (ОДНА СТРОКА) VALUE.PTR: .BLKL 1 ; УКАЗАТЕЛЬ НА БУФЕР ; ВЫВОДИМЫХ ЗНАЧЕНИЙ LINE-COUNTER: .BLKL 1 ; СЧЕТЧИК ЧИСЛА СТРОК ; В ДАМПЕ ПАМЯТИ NUM-VALUES: .BLKL 1 ; ЧИСЛО ПРЕОБРАЗУЕМЫХ ВЕЛИЧИН OUT-PTR: .BLKL 1 ; УКАЗАТЕЛЬ НА БУФЕР ; ВЫВОДА (OUT.BUF) ►END
Приложение Л Ответы на некоторые задачи • Глава 1 2в. С- NVALUES<0 2д. SUMPOS - TOTAL + 47 > О Зз. С —NVALUES >0 Зд. SUMPOS - TOTAL + 47 < 0 • Глава 2 16. 11101. 1д. 101100. 1з. 11. 26. E4F. 2д. 1FF6. 2з. 6F54. 36. 31. 4в. 00111111. 4г. 10011100. 56. 26179. 5д. 510. 66.00100011 10101010. 76. 9В9. 86.1765. 96.-23. 9д. —86. 9и. 127. • Глава 3 1. Диапазон допустимых значений адресов вычислительной ма- шины называется ее адресным пространством. 4. Символическое имя, вызывающее смысловые ассоциации с ло- гикой решения задачи, облегчает его использование при про- граммировании этого решения. 6. Для записи в памяти целых чисел размером длинное слово используется так называемый обратный порядок следования байтов, благодаря чему половина такого длинного слова, содер- жащая младшие разряды числа, а также байт самых младших его разрядов, могут быть использованы в качестве операндов, если сравнительно невелика величина целого числа, подлежа- щего записи в память на хранение. 9. Размер непосредственного операнда команды определяется ее кодом операции. Так, размер непосредственного операнда в ко- манде MOVL равен 5 байт: 1 байт для кода режима адресации и 4 байта для значения целого числа размером длинное слово. Операнды-литералы занимают только два байта: один байт для кода режима адресации, а другой — для целого числа разме- ром байт. Именно поэтому операнды-литералы используются для
486 Приложения представления целых чисел, содержащих очень мало разрядов. 11. FDFF CF 53 DO: 454 FDFB CF 55 FDF7 CF Cl: 459 • Глава 4 3. Тело такого цикла (с проверкой условия его окончания после выполнения операторов тела цикла) обязательно выполняется один раз до проверки необходимости выполнения. ; ЕСЛИ KOUNT < LENGTH CMPL KOUNT, LENGTH BGTR ELSE ; ПРИБАВИТЬ NEXT К SUM И НАРАСТИТЬ KOUNT ADDL2 NEXT, SUM INCL KOUNT BRW ENDIF • ИНАЧЕ ПОЛОЖИТЬ RESULT РАВНЫМ SUM И ; УСТАНОВИТЬ СЧЕТЧИК KOUNT В НУЛЬ ELSE: MOVL SUM, RESULT CLRL KOUNT ; КОНЕЦ ОПЕРАТОРА «ЕСЛИ» ENDIF: 10. ; ДО ТЕХ ПОР, ПОКА DATA > 0 ; ВЫПОЛНЯТЬ В ЦИКЛЕ LOOP: TSTL IN.DATA BLEQ OUT-LOOP ; ПОЛОЖИТЬ SUM = IN-DATA * IN-DATA/2 MULL3 IN-DATA, INDATA, SUM DIVL2 #2, SUM ; ВВОД ЧИСЛА В ОБЛАСТЬ IN-DATA READ-L IN-DATA BRW LOOP 1
Приложения 487 ;КОНЕЦ ЦИКЛА OUT-LOOP: 11. : ДЛЯ KOUNT := 1 ДО 100 ВЫПОЛНЯТЬ В ЦИКЛЕ MOVL # 1, KOUNT LOOP: ; ВВОД ЧИСЛА VALUE И ДОБАВЛЕНИЕ ; СОДЕРЖИМОГО VALUE К СУММЕ SUM READ-L VALUE ADDL2 VALUE, SUM AOBLEQ # 100, KOUNT, LOOP ; КОНЕЦ ЦИКЛА • Глава 5 2. Параметр AFTER : п команды SET BREAK позволяет систе- ме при отладке не реагировать на первые п — 1 точку останова. 6. Команда EXAMINE без параметров (операндов) воспроизво- дит на экране дисплея содержимое поля размером длинное сло- во, непосредственно следующее за последним длинным словом, «обработанным» подобной командой. (По умолчанию принято считать, что размер обрабатываемых данных — длинное слово.) 9. Обращение к отладчику посредством управляющего символа «CONTROL/С» позволяет осуществить повторный пуск этой про- граммы (с помощью команды DEBUG или CONTINUE) при со- хранении ранее установленных значений параметров и контроль- ных точек. После выхода из режима работы с отладчиком по- средством команды EXIT возобновление его работы возможно, однако информация обо всех ранее установленных контрольных точках оказывается потерянной; установленными оказываются только параметры, принимаемые по умолчанию. • Глава 6 3. Ни одна из команд, выполняющих операции над целыми чис- лами размером слово, не воздействует на содержимое верхней половины разрядов регистров, используемых в качестве операн- дов-приемников (поля результата). 5. При использовании команды АСВВ следует помнить, что как до, так и после соответствующего изменения значения параметра цикла адресуемое поле может оказаться на «расстоянии», слиш-
488 Приложения ком большом для доступа к нему при использовании адресации со смещением размером байт, 7. По команде MOVL IN_DATA_4, OUT содержимое длин- ного слова с адресом, значение которого на 4 байта меньше адреса поля IN.DATA, пересылается в поле OUT. По коман- де SUBL3 #4, IN_DATA, OUT из поля IN-DATA размером длинное слово вычитается число 4 и полученный результат за- писывается в поле OUT. • Глава 7 1. BASE + (INDEX-5)* 8 За. 23В + 5 = 240 Зв. 23В + (5*2) = 23В + А = 245 • Глава 8 2. Программы, использующие индексирование, значительно лег- че читаются, чем программы, в которых для тех же целей при- меняется регистровая косвенная адресация. 5. В то время, как недопустимо использование одного и того же регистра одновременно для индексации и для косвенной адреса- ции с автоувеличением или автоуменьшением адреса, один и тот же регистр можно использовать как для индексирования, так и для косвенной регистровой адресации. 9. Сначала вычисляется базовый адрес путем использования со- держимого поля размером длинное слово, адресуемого регист- ром, в соответствии с режимом двойной косвенной адресации. Затем этот адрес модифицируется посредством содержимого ин- дексного регистра путем добавления значения этого содержи- мого к значению адреса или умножения этих значений согласно коду операции команды. 12а. 55 62 С2 12в. 0004 D3 В6 000Э 010А 0000 оюс 12д. 54 00000008 ЕЗ 46 С4 0000 0108 0000 0108 • Глава 9 3. Регистр R0 используется в команде СМРСЗ в качестве счет- чика числа символов в строке, представленной первым операн- дом. В качестве начального значения содержимому счетчика присваивается значение длины этой строки; значение содержи- мого счетчика уменьшается на единицу каждый раз, когда ока- зывается обнаруженными два одинаковых символа (в обеих строках).
Приложения 489 7. Регистр Rl используется в команде LOCC как указатель для строки, в которой осуществляется поиск. В качестве начального значения ему присваивается значение адреса первого символа этой строки; значение содержимого этого указателя увеличи- вается на единицу при каждом отрицательном результате срав- нения (символы не одинаковы). 11. Регистр R1 используется в команде SCANC как указатель для исходной строки. В качестве начального значения ему при- сваивается значение адреса первого символа этой строки; значе- ние содержимого этого указателя увеличивается на 1 каждый раз, когда равен нулю результат операции И между указывае- мым байтом и соответствующим элементом таблицы. 14. Биту-индикатору Z присваивается значение 1, когда резуль- тат выполнения команды поиска является отрицательным («не найдено»). Этому биту признака результата команды сравнения присваивают значение 1 тогда, когда они не обнаруживают раз- личия между двумя сравниваемыми строками. • Глава 10 4. Целые числа размером слово можно загрузить в стек путем загрузки в него с помощью команды PUSHL длинного слова, если эти числа являются его составными частями. 106. ; ЕСЛИ (А < В) ИЛИ (C = D), ТО CMPL А, В BGTR SECOND BRW DO_IT SECOND: CMPL C, D BNEQ NEXT ; ПРИРАЩЕНИЕ СОДЕРЖИМОМУ COUNT DO_IT: INCL COUNT ; КОНЕЦ ОПЕРАЦИЙ «ЕСЛИ» NEXT: 13. Команда CALLG реализуется машиной более эффективно, чем CALLS. Однако при использовании рекурсивных обращений или в тех случаях, когда применение CALLG оказывается не- удобным (из-за проблем загрузки содержимым общего списка параметров), рекомендуется применять команду CALLS. 17 Зак. 483
490 Приложения 16. Подпрограммы создаются как реентерабельные модули толь- ко в тех случаях, когда к ним должны обращаться одновремен- но несколько пользователей. • Глава 11 3. Если при обращении к макроопределению количество факти- ческих параметров превышает количество формальных парамет- ров последнего, то вычислительная система выдает сообщение, об ошибке. 5. Все фактические параметры обращения к макроопределению представляются в форме строк символов в коде ASCII. 10. Функция % LENGTH может быть использована за пределами макроопределения только в повторяющихся блоках. 14. Директива .NARG используется для определения количества параметров, переданных макроопределению. Это оказывается чрезвычайно полезным при организации процедур ввода и вы- вода информации на терминалы системы VAX. ♦ Глава 12 2. Результат выполнения каждой арифметической операции над числами с плавающей точкой может иметь (сохранить не поте- рянными) до 16 десятичных цифр. 6а. 0000 0000 0000 0000 0100 ООП 1000 ОНО 6в. 0000 0000 0000 0000 0100 0100 0010 0001 7а. 12 7в. 3,125 12. 2D34323736 14. 04276D ♦ Глава 13 2. Команда BBS выполняет передачу управления, если прове- ряемый бит равен 1. Команда BBSS передает управление при том же условии, и, кроме того, присваивает проверяемому биту значение 1. 6. Операция сдвига выполняется намного быстрее, чем умноже- ние. 8а. 10000000 8в. 10101111 8д. 11001111 10. MCOMW ALPHA, R7 BICW3 R7, BETA, GAMMA о Глава 14 1. Поскольку число запросов на обращение к периферийным устройствам часто превышает число устройств для управления ресурсами, необходим независимый «арбитр».
Приложения 491 5. При выполнении кодов макрокоманды ^CREATE файл оста- ется открытым, поэтому макрокоманда $OPEN не требуется. 8. Возможность обработки файлов с организацией, отличной от последовательной, включена в подсистему RMS в расчете на ре- шение таких задач, в которых требуется быстрый доступ к за- писям в произвольном порядке. • Глава 15 3. Головной элемент очереди в системе VAX предполагает нали- чие некоторой области памяти, с которой должно начинаться любое обращение к очереди. Кроме того, с помощью головного элемента можно удобно манипулировать пустыми очередями. 7. Для команды CASEx, в которой второй и третий операнды равны соответственно 7 и 12, допустимыми значениями переклю- чателя являются 7, 8, 9, 10, 11, 12 и 13 (при условии, что опре- делены семь смещений). 12. Команда CRC используется для проверки правильности пе- редачи строки символов от одного устройства к другому. 17*
Приложение Е Набор команд системы VAX Код опе- рации Мнемоника команды Выполняемая функция 9D АСВВ Приращение содержимому счетчика, срав- нение с пределом и переход (содержи- мое счетчика —- целое число размером байт) 6F ACBD Приращение содержимому счетчика, срав- нение с пределом и переход (содержи- мое счетчика — число с плавающей точ- кой двойной точности) 4F ACBF Приращение содержимому счетчика, срав- нение с пределом и переход (содержи- мое счетчика — число с плавающей точ- кой) F1 ACBL Приращение содержимому счетчика, срав- нение с пределом и переход (содержи- мое счетчика — целое число размером длинное слово) 3D ACBW Приращение содержимому счетчика, срав- нение с пределом и переход (содержи- мое счетчика — целое число размером слово)
Операнды Признак результата N Z V С Предельное значение содержимого счетчи- ка/rb/, приращение/rb/, текущее значе- ние/mb/, адрес перехода/bw/ ♦ ♦ ♦ — Предельное значение содержимого счетчи- ка/rd/, прирашение/rd/, текущее значе- ние/md/, адрес перехода/bw/ ♦ ♦ ♦ — Предельное значение содержимого счетчи- ка/rf/, приращение/rf/, текущее значе- ние/mf/, адрес перехода/bw/ ♦ ♦ * —- Предельное значение содержимого счетчи- ка/rl/, приращение/rl/, текущее значе- ние/ml/, адрес перехода/bw/ ♦ ♦ ♦ — Предельное значение содержимого счетчи- ка/rw/, приращение/rw/, текущее значе- ние/mw/, адрес перехода/bw/ ♦ ♦ ♦ —• 492 Приложения
58 1 ADAWI Сложение выравненных на границу слов целых чисел размером слово с блоки- ровкой (два операнда) 8(У ADDB2 Сложение целых чисел размером байт (два операнда) 81 ADDB3 Сложение целых чисел размером байт (три операнда) 60 ADDD2 Сложение чисел с плавающей точкой двойной точности (два операнда) 61 ADDD3 Сложение чисел с плавающей точкой двойной точности (три операнда) 40 ADDF2 Сложение чисел с плавающей точкой (два операнда) 41 ADDF3 Сложение чисел с плавающей точкой (три операнда) СО ADDL2 Сложение целых чисел размером длинное слово (два операнда) Cl ADDL3 Сложение целых чисел размером длинное слово (три операнда) 20 ADDP4 Сложение упакованных десятичных чисел (четыре операнда) 21 ADDP6 Сложение упакованных десятичных чисел (шесть операндов) АО ADDW2 Сложение целых чисел размером слово (два операнда)
Слагаемое/rw/, сумма/mw/ Слагаемое/rb/, сумма/mb/ •> * * * Слагаемое 1/гЬ/, слагаемое 2/гЬ/, сум- ♦ ♦ * 0 ма/wb/ Слагаемое/rd/, сумма/md/ ♦ * * 0 Слагаемое 1/rd/, слагаемое 2/rd/, сум- ♦ ♦ * 0 ма/wd/ Слагаемое/rf/, сумма/mf/ ♦ * * 0 Слагаемое 1/rf/, слагаемое 2/rf/, сум- ♦ * * 0 ма/wf/ Слагаемое/г1/, сумма/ml/ ♦ * ♦ ♦ Слагаемое 1/г1/, слагаемое 2/г1/, сум- • * * 0 ма/wl/ Длина слагаемого/rw/, адрес слагаемо- ♦ ♦ ♦ 0 го/ab/, длина суммы/rw/, адрес сум- мы/ab/, [RO-3/wl/] Длина слагаемого 1/rw/, адрес слагаемого ♦ ♦ * 0 1/аЬ/, длина слагаемого 2/rw/, адрес слагаемого 2/аЬ/, длина суммы/rw/, ад- рес суммы/ab/, [RO-5/wl/] Слагаемое/rw/, сумма/mw/ ♦ * ♦ ♦ Приложения
Код опе- рации Мнемоника команды Выполняемая функция Al ADDW3 Сложение целых чисел размером слово (три операнда) D8 ADWC Сложение целых чисел размером длинное слово с использованием бита переноса (два операнда) F3 AOBLEQ Увеличение содержимого счетчика на 1 и переход, если оно меньше или равно предельному значению F2 AOBLSS Увеличение содержимого счетчика на 1 и переход, если оно меньше предельного значения 78 ASHL Арифметический сдвиг содержимого длин- ного слова F8 ASHP Арифметический сдвиг и округление упа- кованного десятичного числа 79 ASHQ Арифметический сдвиг содержимого двой- ного длинного слова El BBC Переход, если бит равен 0 Е5 BBCC Переход, если бит равен 0, и присвоение биту значения 0 Е7 : BBCCI Переход, если бит равен 0, и присвоение биту значения 0 с блокировкой
Операнды Признак результата N Z V С Слагаемое 1/rw/, слагаемое 2/rw/, сум- ма/ww/ Слагаемое/rl/, сумма/ml/ * ♦ ♦ 0 ♦ * ♦ Предельное значение содержимого счетчи- ка/rl/, текущее значение/ml/, адрес пе- рехода/ЬЬ/ ♦ ♦ * — Предельное значение содержимого счетчи- ка/rl/, текущее значение/ml/, адрес пе- рехода/ЬЬ/ ♦ * ♦ — Счетчик/rb/, исходное поле/rl/, поле ре- зультата/wl/ * ♦ ♦ 0 Счетчик/rb/, длина операнда-источни- ка/rw/, адрес операнда-источника/аЬ/, слагаемое округления/rb/, длина опе- ранда-приемника/rw/, адрес операнда- приемника/аЬ/, [RO-3/wl/] ♦ * * 0 Счетчик/rb/, исходное поле/rq/, поле ре- зультата/wq/ ♦ * * 0 Смещение/г1/, база/vb/, адрес перехода/ЬЬ/, [поле битов/mv/] — Смещение/г1/, база/vb/, адрес перехода/ЬЬ/, [поле битов/mv/] — Смещение/г1/, база/vb/, адрес перехода/ЬЬ/, [поле битов/mv/] Приложения
ЕЗ ЕО BBCS BBS Переход, если бит равен 0, и присвоение биту значения 1 Переход, если бит равен 1 Е4 BBSC Переход, если бит равен 1, и присвоение биту значения 0 Е‘2 BBSS Переход, если бит равен 1, и присвоение биту значения 1 Е6 BBSSI Переход, если бит равен 1, и присвоение биту значения 1с блокировкой 1Е вес Переход, если бит переноса равен 0 1F BCS Переход, если бит переноса равен 1 13 BEQL Переход, если равно 13 BEQLU Переход, если равно (сравнивались числа без знака) 18 BGEQ Переход, если больше или равно 1Е BGEQU Переход, если больше или равно (сравни- вались числа без знака) 14 BGTR Переход, если больше 1А BGTRU Переход, если больше (сравнивались чис- ла без знака) 8А BICB2 Присвоение значения 0 битам байта (два операнда) 8В BICB3 Присвоение значения 0 битам байта (три операнда) СА BICL2 Присвоение значения 0 битам длинного слова (два операнда) СВ BICL3 Присвоение значения 0 битам длинного слова (три операнда)
Смещение/rl/, база/vb/, адрес перехо- — да/bb/, [поле битов/mv/] Смещение/г1/, база/vb/, адрес перехода/ЬЬ/, — — — — [поле битов/rv/] Смещение/г1/, база/vb/, адрес перехода/ЬЬ/, — —. ___ __ [поле битов/mv/] Смещение/г1/, база/vb/, адрес перехода/ЬЬ/, — [поле битов/mv/] Смещение/г1/, база/vb/, адрес перехода/ЬЬ/, — — — —. [поле битов/mv/] Адрес перехода/ЬЬ/ — Адрес перехода/ЬЬ/ — Адрес перехода/ЬЬ/ — Адрес перехода/ЬЬ/ — Адрес перехода/ЬЬ/ — Адрес перехода/ЬЬ/ — Адрес перехода/ЬЬ/ «I. «— । Адрес перехода/ЬЬ/ — Маска/rb/, поле результата/mb/ * * 0 — Маска/rb/, исходное поле/rb/, поле резуль- ♦ * 0 — тата/wb/ Маска/rl/, поле результата/ml/ * * 0 — Маска/rl/, исходное поле/rl/, поле резуль- * ♦ 0 — тата/wl/ Приложения
Код опе- рации Мнемоника команды Выполняемая функция В9 BICPSW Присвоение значения 0 битам слова со- стояния процессора АА BICW2 Присвоение значения 0 битам слова (два операнда) АВ BICW3 Присвоение значения 0 битам слова (три операнда) 88 BISB2 Присвоение значения 1 битам байта (два операнда) 89 BISB3 Присвоение значения 1 битам байта (три операнда) С8 BISL2 Присвоение значения 1 битам длинного слова (два операнда) С9 BISL3 Присвоение значения 1 битам длинного слова (три операнда) В8 BISPSW Присвоение значения 1 битам слова со- стояния процессора А8 BISW2 Присвоение значения 1 битам слова (два операнда) А9 BISW3 Присвоение значения 1 битам слова (три операнда) 93 BITB Проверка значений битов байта D3 BITL Проверка значений битов длинного слова ВЗ BITW Проверка значений битов слова Е9 BLBC Переход, если бит младшего разряда ра- вен 0
Операнды Признак результата N Z V С Маска/rw/ ♦ * ♦ ♦ Маска/rw/, поле результата/mw/ ♦ ♦ 0 — Маска/rw/, исходное поле/rw/, поле ре- зультата/ww/ ♦ ♦ 0 - Маска/rb/, поле результата/mb/ * ♦ 0 - Маска/rb/, исходное поле/rb/, поле резуль- тата/wb/ * ♦ 0 - Маска/rl/, поле результата/ml/ * * 0 — Маска/rl/, исходное поле/rl/, поле резуль- тата/wl/ ♦ ♦ 0 — Маска/rw/ ♦ * ♦ ♦ Маска/rw/, поле результата/mw/ ♦ * 0 — Маска/rw/, исходное поле/rw/, поле ре- зультата/ww/ ♦ * 0 — Маска/rb/, тестируемое поле/rb/ ♦ * 0 — Маска/rl/, тестируемое поле/rl/ * ♦ 0 - Маска/rw/, тестируемое поле/rw/ * ♦ 0 - Исходное поле/rl/, адрес перехода/ЬЬ/ — —— — — $ Приложения
Е8 BLBS Переход, если бит младшего разряда ра- вен 1 15 BLEQ Переход, если меньше или равно IB BLEQU Переход, если меньше или равно (сравни- вались числа без знака) 19 BLSS Переход, если меньше IF BLSSU Переход, если меньше (сравнивались чис- ла без знака) 12 BNEQ Переход, если не равно 12 BNEQU Переход, если не равно (сравнивались числа без знака) 03 BPT Прерывание в контрольной точке 11 BRB Безусловный переход (смещение — «адрес перехода» — размером байт) 31 BRW Безусловный переход (смещение —- «адрес перехода» — размером слово) 10 BSBB Переход к подпрограмме (смещение — «адрес перехода» — размером байт) 30 BSBW Переход к подпрограмме (смещение — «адрес перехода» — размером слово) 1C BVC Переход при отсутствии переполнения (смещение — «адрес перехода» — разме- ром байт) ID BVS Переход по переполнению (смещение — «адрес перехода» — размером байт) FA CALLG Вызов процедуры с передачей параметров через общий список FB CALLS Вызов процедуры с использованием стека для передачи списка параметров
Исходное поле/г1Л адрес перехода/ЬЬ/ — Адрес перехода/ЬЬ/ Адрес перехода/ЬЬ/ — Адрес перехода/ЬЬ/ Адрес перехода/ЬЬ/ — Адрес перехода/ЬЬ/ Адрес перехода/ЬЬ/ — [—(KSP)/w*/] Адрес перехода/ЬЬ/ 0 0 0 0 Адрес перехода/bw/ — Адрес перехода/bb/, [— (SP)/wl/] — Адрес перехода/bw/, [—(SP)/wl/] — Адрес перехода/ЬЬ/ — Адрес перехода/ЬЬ/ — Адрес списка параметров/аЬ/, адрес про- цедуры/ab/, [— (SP)/w*/] Количество параметров/rl/, адрес пропе- дуры/ab/, [—(SP)/w*/] 0 0 0 0 0 0 0 0 Приложения CO
Код опе- рации Мнемоника команды Выполняемые функции 8F CASEB Переключение управления (переключа- тель — целое число размером байт) CF CASEL Переключение управления (переключа- тель — целое число размером длинное слово) AF CASEW Переключение управления (переключа- тель —- целое число размером слово) BD СИМЕ Переключение процессора на режим «вы- полнения» ВС СНМК Переключение процессора на режим «яд- ра» BE CHMS Переключение процессора на режим «су- первизор» BF CHMLJ Переключение процессора на режим «пользователя» 94 CLRB Очистка байта 7С CLRD Очистка поля для размещения числа с плавающей точкой двойной точности D4 CLRF Очистка поля для размещения числа с плавающей точкой D4 CLRL Очистка длинного слова 7С CLRQ Очистка двойного длинного слова В4 CLRW Очистка слова 91 СМРВ Сравнение целых чисел размером байт
Операнды Признак результа N Z V та с Переключатель/rb/, база/rb/, верхняя гра- ница/rb/, список адресов перехода/bw/ * ♦ 0 * Переключатель/г1/, база/rl/, верхняя гра- ница/rl/, список адресов перехода/bw/ * * 0 ♦ Переключатель/rw/, база/rw/, верхняя гра- ница/rw/, список адресов перехода/bw/ * * 0 * Параметр/rw/, [— (ySP)/w*/] y=MINU (Е, текущий режим PSL) ООО 0 Параметр/rw/, [—(KSP)/w*/] ООО 0 Параметр/rw/, [—(ySP)/w*/l y = MXNU (S, текущий режим PSL) ООО 0 Параметр/rw/, [—(SP)/w*/] ООО 0 Обрабатываемое поле/wb/ 0 1 0 — Обрабатываемое поле/wd/ 0 1 0 — Обрабатываемое поле/wf/ 0 1 0 — Обрабатываемое поле/wl/ 0 1 0 — Обрабатываемое поле/wq/ 0 1 0 — Обрабатываемое поле/ww/ 0 1 0 — Операнд 1/гЬ/, операнд 2/гЬ/ ♦ * 0 * Приложения
29 СМРСЗ 2D СМРС5 71 CMPD 51 CMPF D1 CMPL 35 СМРРЗ 37 СМРР4 ЕС CMPV В1 CMPW ED CMPZV ОВ CRC GC CVTBD 4С CVTBF 98 CVTBL Сравнение строк символов (три операн- операн- да) Сравнение дов) строк символов (пять Сравнение двойной чисел с плавающей точности точкой Сравнение чисел с плавающей точкой Сравнение целых чисел размером длин- ное слово Сравнение упакованных десятичных чисел (три операнда) Сравнение упакованных десятичных чисел (четыре операнда) Сравнение полей битов (с дополнением первого поля до 32 битов битом знака) Сравнение целых чисел размером слово Сравнение полей битов (с дополнением первого поля до 32 бит битом 0) Циклическая проверка на избыточность Преобразование целого числа размером байт в число с плавающей точкой двой- ной точности Преобразование целого числа размером байт в число с плавающей точкой Преобразование целого числа размером байт в целое число размером длинное слово
Длина/rw/, строка 1/аЬ/, строка 2/аЬ/, [RO-3/wl/] Длина строки 1/rw/, строка 1/аЬ/, сим- вол-заполнитель/гЬ/, длина строки 2/rw/, строка 2/аЬ/, [RO-3/wl/] Операнд 1/rd/, операнд 2/rd/ ♦ ♦ 0 * * * ♦ 0 ♦ ♦ 0 0 Операнд 1/rf/, операнд 2/rf/ * ♦ 0 0 Операнд 1/г1/, операнд 2/г1/ ♦ ♦ 0 * Длина/rw/, адрес 1/аЬ/, адрес 2/аЬ/, [RO-3/wl/] * *00 Длина 1/rw/, адрес 1/аЬ/, длина 2/rw/, адрес 2/аЬ/, [RO-3/wI/] ♦ ♦ 0 0 Смещение/г1/, размер/rb/, база/vb/, [поле битов/rv/], операнд-источник/rl/ * * 0 * Операнд 1/rw/, операнд 2/rw/ * ♦ 0 ♦ Смещение/rl/, размер/rb/, база/vb/, [поле битов/rv/], операнд-источник/rl/ * ♦ 0 ♦ Таблица/аЬ/, исходные символы/rl/, длина строки/rw/, поток/ab/, [RO-5/wl/], опе- ранд-приемник/wl/ * ♦ 0 - Операнд-источник/rb/, операнд-прием - ник/wd/ * * * 0 Операнд-источник/rb/, операнд- приемник/wf/ * ♦ * 0 Операнд-источник/rb/, операнд- приемник/wl/ ♦ * ♦ 0 Приложения 499
Код опе- рации Мнемоника команды Выполняемая функция 99 CVTBW Преобразование целого числа размером байт в целое число размером слово 68 CVTDB Преобразование числа с плавающей точ- кой двойной точности в целое число размером байт 76 CVTDF Преобразование числа с плавающей точ- кой двойной точности в число с пла- вающей точкой 6А CVTDL Преобразование числа с плавающей точ- кой двойной точности в целое число размером длинное слово 69 CVTDW Преобразование числа с плавающей точ- кой двойной точности в целое число размером слово 48 CVTFB Преобразование числа с плавающей точ- кой в целое число размером байт 56 CVTFD Преобразование числа с плавающей точ- кой в число с плавающей точкой двой- ной точности 4А CVTFL Преобразование числа с плавающей точ- кой в целое число размером длинное слово 49 CVTFW Преобразование числа с плавающей точ- кой в целое число размером слово
Операнды Признак результата N Z V с Операнд-источник/rb/, операнд- прпемник/ww/ * * * 0 Операнд-источнпк/rd/, операнд- приемник/wb/ * * * 0 Операнд-источник/rd/, операнд- приемник/wf/ * * * 0 Операнд-источник/rd/, операнд- приемник/wl/ * * * 0 Операнд-источник/rd/, операнд- приемник/ww/ * ♦ * 0 Операнд-источник/rf/, операнд- приемник/wb/ * * * 0 Операнд-источник/rf/, операнд- приемник/wd/ * * * 0 Операнд-источник/rf/, операнд- приемник/wl/ * * * 0 Операнд-источник/rf/, операнд- приемник/ww/ * ♦ ♦ 0 SOO Приложения
F6 CVTLB 6Е CVTLD 4Е CVTLF F9 CVTLP F7 CVTLW 36 CVTPL 08 CVTPS 24 CVTPT Преобразование целого числа размером длинное слово в целое число размером байт Преобразование целого числа размером длинное слово в число с плавающей точкой двойной точности Преобразование целого числа размером длинное слово в число с плавающей точкой Преобразование целого числа размером длинное слово в упакованное десятич- ное число Преобразование целого числа размером длинное слово в целое число размером слово Преобразование упакованного десятично- го числа в целое число размером длин- ное слово Преобразование упакованного десятично- го числа в числовую строку с раздель- ным ведущим знаком Преобразование упакованного десятично- го числа в числовую строку с ведомым знаком
Операнд-источник/rl/, операнд- приемник/wb/ ♦ ♦ ♦ 0 Операнд-источник/rl/, операнд- приемник/wd/ * ♦ ♦ 0 Операнд-источник/rl/, операнд- приемник/wf/ * * * 0 Длинное слово/rl/, длина упакованных данных/rw/, адрес упакованных дан- ных/ab/, [RO-3/wl/] * * ♦ 0 Операнд-источник/rl/, операнд- приемник/ww/ ♦ ♦ ♦ о Длина упакованных данных/rw/, адрес упакованных данных/аЬ/, [RO-3/wl/], длинное слово/wl/ * ♦ ♦ 0 Длина упакованных данных/rw/, адрес упакованных данных/ab/, длина строки с ведущим знаком/rw/, адрес строки с ведущим знаком/аЬ/, [RO-3/wl/] * * ♦ 0 Длина упакованных данных/rw/, адрес упакованных данных/ab/, адрес табли- цы/ab/, длина строки с ведомым зна- ком/rw/, адрес строки с ведомым зна- ком/ab/, [RO-3/wl/J ♦ * * 0 Приложения
Код опе- рации Мнемоника команды Выполняемая функция 6В CVTRDL Преобразование с округлением числа с плавающей точкой двойной точности в целое число размером длинное слово 4В CVTRFL Преобразование с округлением числа с плавающей точкой в целое число разме- ром длинное слово 09 CVTSP Преобразование числов'ой строки с раз- дельным ведущим знаком в упакован- ное десятичное число 26 CVTTP Преобразование числовой строки с ведо- мым знаком в упакованное десятичное число 33 CVTWB Преобразование целого числа размером слово в целое число размером байт 6D CVTWD Преобразование целого числа размером слово в число с плавающей точкой двойной точности 4D CVTWF Преобразование целого числа размером слово в число с плавающей точкой 32 CVTWL Преобразование целого числа размером слово в целое число размером длинное слово
Операнды Признак результата N Z V С Операнд-источник/rd/, операнд- приемник/wl/ * * * 0 Операнд-источник/rf/, операнд- приемник/wl/ * * ♦ 0 Длина строки с ведущим знаком/rw/, ад- рес строки с ведущим знаком/ab/, дли- на упакованных данных/rw/, адрес упа- кованных данных/аЬ/, [RO-3/wl/] * ♦ * 0 Длина строки с ведомым знаком/rw/, ад- рес троки с ведомым знаком/ab/, адрес таблицы/ab/, длина упакованных дан- ных/rw/, адрес упакованных данных/аЬ/, [RO-3/wl/l * ♦ * 0 Операнд-источник/rw/, операнд- приемник/wb/ * * * 0 Операнд-источник/rw/, операнд- приемник/wd/ * ♦ * 0 Операнд-исотчник/rw/, операнд- приемник/wf/ ♦ * * 0 Операнд-источник/rw/, операнд- приемник/wl/ ♦ ♦ * 0 502 Приложения
97 DECB Уменьшение на 1 целого числа размером байт D7 DECL Уменьшение на 1 целого числа размером длинное слово В7 DECW Уменьшение на I целого числа размером слово 86 DIVB2 Деление целых чисел размером байт (два операнда) 87 DIVB3 Деление целых чисел размером байт (три операнда) 66 DIVD2 Деление чисел с плавающей точкой двой- ной точности (два операнда) 67 DIVD3 Деление чисел с плавающей точкой двой- ной точности (три операнда) 46 DIVF2 Деление чисел с плавающей точкой (два операнда) 47 DIVF3 Деление чисел с плавающей точкой (три операнда) С6 DIVL2 Деление целых чисел размером длинное слово (два операнда) С7 DIVL3 Деление целых чисел размером длинное слово (три операнда) 27 DIVP Деление упакованных десятичных чисел А6 DIVW2 Деление целых чисел размером слово (два операнда)
Адрес операнда/mb/ * ♦ * * Адрес операнда/ml/ * « * ♦ Адрес операнда/mw/ * * * * Делитель/гЬ/, частное/mb/ * * ♦ 0 Делитель/гЬ/, делимое/rb/, частное/wb/ * * * 0 Делитель/rd/, частное/md/ * * * 0 Делитель/rd/, делимое/rd/, частное/wd/ * * * 0 Делитель/rf/, частное/mf/ ♦ ♦ ♦ 0 Делитель/rf/, делимое/rf/, частное/wf/ ♦ * ♦ 0 Делитель/г1/, частное/ml/ ♦ * ♦ 0 Делитель/г1/, делимое/rl/, частное/wl/ * * * 0 (Длина делителя/rw/, адрес делителя/ab/, ♦ ♦ ♦ 0 длина делимого/rw/, адрес делимого/ab/, длина частного/rw/, адрес частного/аЬ/, fR0-5/wl/,—16(SP)1 (SP)/wb/J Делитель/rw/, частное/mw/ * * * 0 Приложения
Код опе- рации Мнемоника команды Выполняемая функция А7 DIVW3 Деление целых чисел размером слово (три операнда) 38 EDITPC Редактирование упакованного десятично- го числа 7В EDIV Деление расширенное 74 EMODD Умножение чисел с плавающей точкой двойной точности с расширением моду- ля множителя 54 EMODF Умножение чисел с плавающей точкой с расширением модуля множителя 7А EMUL Умножение расширенное ЕЕ EXTV Размещение строки битов в поле разме- ром длинное слово с добавлением битов знака EF EXTZV Размещение строки битов в поле разме- ром длинное слово с добавлением нулей ЕВ FFC Поиск первого бита, равного 0 ЕА FFS Поиск первого бита, равного 1
Операнды Признак результата N z V С Делитель/rw/, делимое/rw/, частное/ww/ * * ♦ 0 Длина исходной строки/rw/, адрес исход- ной строки/аЬ/, шаблон редактирова- ния/ab/, адрес результата/аЬ/, [RO-5/wl/] ♦ * ♦ * Делитель/г1/, делимое/rq/, частное/wl/, * * ♦ 0 остаток/wl/ Множитель/rd/, расширение множителя/rb/, множимое/rd/, целая часть результа- та/wl/, дробная часть результата/wd/ ♦ ♦ * 0 Множитель/rf/, расширение множителя/rb/, множимое/rf/, целая часть результа- ♦ ♦ ♦ 0 та/wl/, дробная часть результата/wf/ Множитель/rl/, множимое/rl/, второе сла- *♦00 гаемое/rl/, произведение/wq/ Смещение/г1/, длина/rb/, база/vb/, [поле ♦ ♦ 0 — битов/rv/], поле результата/wl/ Смещение/г1/, длина/rb/, база/vb/, [поле ♦ ♦ 0 — битов/rv/], поле результата/wl/ Смещение/rl/, размер/rb/, база/vb/, [поле 0*00 битов/rv/], поле результата/wl/ Смещение/г1/, размер/rb/, база/vb/, [поле 0*00 битов/rv/], поле результата/wl/ Приложения СИ
18 Зак. 483 00 HALT Останов (только в режиме «ядра») 96 INCB Увеличение на 1 целого числа размером байт D6 INCL Увеличение на 1 целого числа размером длинное слово В6 INCW Увеличение на 1 целого числа размером слово 0А INDEX Вычисление и проверка индекса на диапа- зон возможных значений ОЕ INSQUE Включение в очередь F0 INSV Перемещение подстроки битов из поля размером длинное слово в поле битов 17 JMP Безусловный переход 16 JSB Переход к подпрограмме 06 LDPCTX Загрузка контекста процессора ЗА LOCC Определение местоположения символа 39 МАТСНС Поиск подстроки символов 92 MCOMB Вычисление дополнительного кода содер- жимого поля размером байт D2 MCOML Вычисление дополнительного кода содер- жимого поля размером длинное слово В2 MCOMW Вычисление дополнительного кода содер- жимого поля размером слово
[_(KSP)/w*/] Адрес операнда/mb/ ♦ ♦ « ♦ ♦ ♦ ♦ ♦ Адрес операнда/ml/ ♦ ♦ ♦ ♦ Адрес операнда/mw/ ♦ ♦ ♦ ♦ Индекс элемента массива/rl/, нижняя гра- ница/rl/, верхняя гранИЦа/rl/, размер элемента/rl/, начальное значение/rl/, вы- ходной индекс/wl/ ♦ ♦00 Вставляемый элемент/ab/, предшествую- щий элемент/wl/ ♦ ♦ 0 ♦ Исходное поле/rl/, смещение/rl/, дли- на/rb/, база/vb/, [поле битов/wv/] 0 0 0 - Адрес перехода/аЬ/ — Адрес перехода/ab/, [—(SP)+/wl/] — [PCB/r*/,-(KSP)/w*/] — Символ/rb/, длина строки/rw/, адрес стро- ки/ab/, [RO-1/wl/] 0*00 Длина искомой подстроки/rw/, искомая подстрока/ab/, длина исходной стро- ки/rw/, исходная строка/аЬ/, [RO-3/wl/] 0^00 Исходное поле/rb/, поле результата/wb/ ♦ ♦ 0 — Исходное поле/rl/, поле результата/wl/ ♦ ♦ 0 - Исходное поле/rw/, поле результата/ww/ ♦ ♦ 0 — vmiojicovnd ц
Код опе- рации Мнемоника команды Выполняемая функция DB MFPR Извлечение содержимого привилегирован- ного регистра (только в режиме «яд- ра>) 8Е MNEGB Пересылка целого числа размером байт с изменением знака на противоположный 72 MNEGD Пересылка числа с плавающей точкой двойной точности с изменением знака на противоположный 52 MNEGF Пересылка числа с плавающей точкой с изменением знака на противоположный СЕ MNEGL Пересылка целого числа размером длин- ное слово с изменением знака на про- тивоположный АЕ MNEGW Пересылка целого числа размером слово с изменением знака на противополож- ный 9Е MOVAB Пересылка адреса целого числа размером байт 7Е MOVAD Пересылка адреса числа с плавающей точкой двойной точности DE MOVAF Пересылка адреса числа с плавающей точкой DE MOVAL Пересылка адреса целого числа размером длинное слово
Операнды Признак результата N Z V С Привилегированный регистр/rl/, операнд- ♦ ♦ 0 - приемник/wl/ Исходное поле/rb/, поле результата/wb/ ♦ ♦ ♦ ♦ Исходное поле/rd/, поле результата/wd/ • •00 Исходное поле/rf/, поле результата/wf/ ♦ ♦00 Исходное поле/rl/, поле результата/wl/ ♦ ♦ ♦ ♦ Исходное поле/rw/, поле результата/ww/ ♦ ♦ ♦ ♦ Исходное поле/ab/, поле результата/wl/ ♦ ♦ 0 - Исходное поле/ad/, поле результата/wl/ ♦ ♦ 0 - Исходное поле/af/, поле результата/wl/ ♦ ♦ 0 - Исходное поле/al/, поле результата/wl/ ♦ ♦ 0 — Приложения i
s 7E MOVAQ Пересылка адреса целого числа размером ♦ двойное длинное слово ЗЕ MOVAW Пересылка адреса целого числа размером слово 90 MOVB Пересылка целого числа размером байт 28 MOVC3 Пересылка строк символов (три операн- да) 2C MOVC5 Пересылка строк символов (пять операн- дов) 70 MOVD Пересылка числа с плавающей точкой двойной точности 50 MOVF Пересылка числа с плавающей точкой DO MOVL Пересылка целого числа размером длин- ное слово 34 MOVP Пересылка упакованного десятичного чис- ла pc MOVPSL Пересылка содержимого длинного слова состояния процессора 7D MOVQ Пересылка целого числа размером двой- ное длинное слово 2E MOVTC Пересылка строки символов с перекоди- рованием
Исходное поле/aq/, поле результата/wl/ Исходное поле/aw/, поле результата/wl/ Исходное поле/rb/, поле результата/wb/ Длина строки/rw/, адрес исходного по- ля/ab/, адрес поля результата/аЬ/, [RO-5/wl/] Длина исходной строки/rw/, адрес исход- ного поля/ab/, символ-заполнитель/rb/, длина 2/rw/, адрес результирующей строки/ab/, [RO-5/wl/] Исходное поле/rd/, поле результата/wd/ Исходное поле/rf/, поле результата/wf/ Исходное поле/rl/, поле результата/wl/ Длина/rw/, операнд-источник/ab/, операнд- приемник/ab/, [RO-3/wl/] Операнд-приемник/wl/ Исходное поле/rq/, поле результата/wq/ Длина исходной строки/rw/, адрес исход- ной строки/ab/, символ-заполнитель/rb/, адрес таблицы перекодировки/ab/, дли- на поля результата/rw/, адрес поля ре- зультата/аЬ/, [RO-5/wl/] ♦ ♦ 0 — ♦ ♦ о — ♦ ♦ о - 0 10 0 ♦ ♦ о ♦ ♦ ♦ о — ♦ ♦ о — ♦ ♦ о — ♦ ♦ о - ♦ ♦ 0 — * « о * Приложения
Код опе- рации Мнемоника команды Выполняемая функция 2F MOVTUC Пересылка строки символов с перекодиро- ванием до обнаружения определенного символа ВО MOVW Пересылка целого числа размером слово 9А MOVZBL Пересылка целого числа размером байт в поле размером длинное слово с допол- нением его содержимого двоичными ну- лями 9В MOVZBW Пересылка целого числа размером байт в поле размером слово с дополнением его содержимого двоичными нулями ЗС MOVZWL Пересылка целого числа размером слово в поле размером длинное слово с до- полнением его содержимого двоичными нулями DA MTPR Запись в привилегированный регистр 84 MULB2 Умножение целых чисел размером байт (д&ъ операнда) 85 MULB3 Умножение целых чисел размером байт (три операнда) 64 MULD2 Умножение чисел с плавающей точкой двойной точности (два операнда)
Операнды Признак результата N Z V С Длина исходной строки/rw/, адрес исход- ♦ ♦ ♦ ♦ ной строки/ab/, символ-ограничитель/rb/, адрес таблицы перекодировки/ab/, дли- на поля результата/rw/, адрес поля ре- зультата/аЬ/, [RO-5/wl/] Исходное поле/rw/, поле результата/ww/ ♦ * 0 — Исходное поле/rb/, поле результата/wl/ 0 ♦ 0 — Исходное поле/rb/, поле результата/ww/ 0*0 — Исходное поле/rw/, поле результата/wl/ 0*0- Операнд-источник/rl/, привилегированный ♦ ♦ о —• регистр/wl/ Множитель/гЬ/, произведение/mb/ ♦ ♦ ♦ 0 Множитель/гЬ/, множимое/rb/, произведе- ♦ ♦ ♦ 0 ние/wb/ Множитель/rd/, произведение/md/ ♦ ♦ ♦ 0 Приложения сл g
65 MULD3 Умножение чисел с плавающей точкой двойной точности (три операнда) 44 MULF2 Умножение чисел с плавающей точкой (два операнда) 45 MULF3 Умножение чисел с плавающей точкой (три операнда) С4 MULL2 Умножение целых чисел размером длин- ное слово операнда) С5 MULL3 Умножение целых чисел размером длин- ное слово (три операнда) 25 MULP Умножение упакованных десятичных чи- сел А4 MULW2 Умножение целых чисел размером слово (два операнда) А5 MULW3 Умножение целых чисел размером слово (три операнда) 01 NOP Нет операции 75 POLYD Вычисление многочлена посредством арифметики чисел с плавающей точкой двойной точности 55 POLYF Вычисление многочлена посредством арифметики чисел с плавающей точкой ВА POPR Извлечение содержимого регистров из стека ОС PROBER Проверка доступности операнда для чте- ния Множитель/г(1/, множимое/rd/, произведе- ние/wd/ Множитель/rf/, произведение/mf/ ♦ ♦ ♦ 0 * ♦ ♦ 0 Множитель/rf/, множимое/rf/, произведе- ♦ ♦ ♦ 0 ние/wf/ Множитель/г1/, произведение/ml/ * ♦ ♦ 0 Множитель/г1/, множимое/rl/, произведе- ♦ ♦ ♦ 0 ние/wl/ Длина множителя/rw/, множитель/ab/, * ♦ ♦ 0 длина множимого/rw/, множимое/ab/, длина произведения/rw/, произведе- ние/ab/, [RO-5/wl/] Множитель/rw/, произведение/mw/ * ♦ * 0 Множитель/rw/, множимое/rw/, произве- * ♦ ♦ 0 дение/ww/ _____ Аргумент/rd/, степень/rw/, адрес табли- ♦ ♦ ♦ 0 цы коэффициентов/ab/, [RO-5/wl/] Аргумент/rf/, степень/rw/, адрес таблицы * * ♦ 0 коэффициентов/ab/, [RO-3/wl/J Маска/rw/, [(SP)+/r*/] — Режим/гЬ/, длина/rw/, база/аЬ/ 0*0 — Приложения 509
Код опе- рации Мнемоника команды Выполняемая функция 0D PROBEW Проверка доступности операнда для за- писи 9F PUSHAB Загрузка в стек адреса целого числа раз- мером байт 7F PUSHAD Загрузка в стек адреса числа с плаваю- щей точкой двойной точности DF PUSHAF Загрузка в стек адреса числа с плаваю- щей точкой DF PUSHAL Загрузка в стек адреса целого числа раз- мером длинное слово 7F PUSHAQ Загрузка в стек адреса целого числа раз- мером двойное длинное слово 3F PUSHAW Загрузка в стек адреса целого числа раз- мером слово DD PUSHL Загрузка в стек целого числа размером длинное слово ВВ PUSHR Загрузка в стек содержимого регистров 02 REI Возврат из процедуры обработки особой ситуации или прерывания 0F REMQUE Удаление из очереди
Операнды Признак результата N Z V С Режим/rb/, длина/rw/, база/аЪ/ 0*0- Опер ан д-источн ик/ab/, [— (S Р) /w 1/] ♦ ♦ 0 - Операнд-источник/ad/, [—(SP)/wl/J ♦ ♦ 0 — Операнд-источник/af/, [—(SP)/wl/] ♦ ♦ 0 — Операнд-источник/а1/, [—(SP)/wl/J ♦ ♦ 0 - Операнд-источник/aq/, [—(SP)/wl/] ♦ ♦ 0 - Операнд-источник/aw/, [— (SP)/wl/] ♦ ♦ 0 - Операнд-источник/rl/, £—(SP)/wl/J ♦ ♦ 0 — Маска/rw/, [—(SP)/w*/] — —- [(SP)+/r*/] ♦ ♦ ♦ ♦ Удаляемый элемент/ab/, адрес/wl/ ♦ ♦ ♦ ♦ 510 Приложения
04 RET Возврат из процедуры 9С ROTL Циклический сдвиг содержимого длинно- го слова 05 RSB Возврат из подпрограммы D9 SBWC Вычитание с использованием бита перено- са 2А SCANC Поиск определенных символов в строке ЗВ SKPC Пропуск символа F4 SOBGEQ Уменьшение содержимого счетчика на 1 и переход, если больше или равно F5 SOBGTR Уменьшение содержимого счетчика на 1 и переход, если больше 2В SPANC Пропуск символов, предшествующих опре- деленным 82 SUBB2 Вычитание целых чисел размером байт (два операнда) 83 SUBB3 Вычитание целых чисел размером байт (три операнда) 62 SUBD2 Вычитание чисел с плавающей точкой двойной точности (два операнда)
♦ ♦ ♦ * [(SP)+/r*/] Счетчик/rb/, исходное поле/rl/, поле ре- зультата/wl/ [(SP)+/rl/] Вычитаемое/rl/, разность/ml/ 1 1 • о 1 * • 1 * « 1 * Длина строки/rw/, адрес строки/ab/, адрес 0*00 таблицы/аЬ/, маска/rb/, [RO-3/wl/] Символ/rb/, длина строки/rw/, адрес 0*00 строки/ab/, [RO-1/wl/] Параметр/ml/, адрес перехода/ЬЬ/ * * * — Параметр/ml/, адрес перехода/bb/ Длина строки/rw/, адрес строки/ab/, ад- рес таблицы/ab/, маска/rb/, [RO-3/wl/] Вычитаемое/гЬ/, разность/mb/ О * О О Вычитаемое/гЬ/, уменыпаемое/rb/, раз- ность/wb/ О Вычитаемое/rd/, разность/md/ О Приложения
Код опе- рации Мнемоника команды, Выполняемая функция 63 SUBD3 Вычитание чисел с плавающей точкой двойной точности (три операнда) 42 SUBF2 Вычитание чисел с плавающей точкой (два операнда) 43 SUBF3 Вычитание чисел с плавающей точкой (три операнда) С2 SUBL2 Вычитание целых чисел размером длин- ное слово (два операнда) СЗ SOBL3 Вычитание целых чисел размером длин- ное слово (три операнда) 22 SUBP4 Вычитание упакованных десятичных чисел (четыре операнда) 23 SUBP6 Вычитание упакованных десятичных чисел (шесть операндов) А2 SUBW2 Вычитание целых чисел размером слово (два операнда) АЗ SUBW3 Вычитание целых чисел размером слово (три операнда)
Операнды Признак результата N Z V С Вычитаемое/rd/, уменьшаемое/rd/, раз- ность/wd/ ♦ ♦ ♦ 0 Вычитаемое/rf/, разность/mf/ » ♦ ♦ 0 Вычитаемое/rf/, уменыпаемое/rf/, раз- ность/wf/ ♦ ♦ ♦ 0 Вычитаемое/г1/, разность/ml/ ♦ ♦ ♦ ♦ Вычитаемое/г1/, уменыиаемое/rl/, раз- ность/wl/ ♦ ♦ ♦ 0 Длина вычитаемого/rw/, адрес вычитае- мого/ab/, длина разности/rw/, адрес раз- ности/ab/, [RO-3/wl/] ♦ * ♦ 0 Длина вычитаемого/rw/, адрес вычитаемо- го/ab/, длина уменииаемого/rw/, адрес уменьшаемого/ab/, длина разности/rw/, адрес разности/аЬ/, [RO-5/wl/] ♦ ♦ ♦ 0 Вычитаемое/rw/, разность/mw/ ♦ ♦ ♦ ♦ Вычитаемое/rw/, уменьшаемое/rw/, раз- ность/ww/ ♦ * ♦ 0 Приложения
07 SVPCTX Сохранение контекста процессора (только в режиме «ядра») [(SP)+/r*/,—(KSP)/w*/] 95 TSTB Тестирование целого числа размером байт Обрабатываемое поле/rb/ *•00 73 TSTD Тестирование числа с плавающей точкой двойной точности Обрабатываемое поле/rd/ «•00 53 TSTF Тестирование числа с плавающей точкой Обрабатываемое поле/rf/ ««00 D5 TSTL Тестирование целого числа размером длинное слово Обрабатываемое поле/г1/ ««00 В5 TSTW Тестирование целого числа размером сло- во Обрабатываемое поле/rw/ ««00 FC XFC Вызов средств расширения набора команд Определяются пользователем 0 0 0 0 8С X0RB2 Исключающее ИЛИ над содержимым байта (два операнда) Маска/rb/, поле результата/mb/ ♦ « 0 - 8D X0RB3 Исключающее ИЛИ над содержимым байта (три операнда) Маска/rb/, исходное поле/rb/, поле ре- зультата/wb/ ♦ ♦ 0 - СС X0RL2 Исключающее ИЛИ над содержимым длинного слова (два операнда) Маска/rl/, поле результата/ml/ ♦ ♦ 0 - CD X0RL3 Исключающее ИЛИ над содержимым длинного слова (три операнда) Маска/rl/, исходное поле/rl/, поле резуль- тата/wl/ ♦ ♦ 0 - АС X0RW2 Исключающее ИЛИ над содержимым сло- ва (два операнда) Маска/rw/, поле результата/mw/ ♦ ♦ 0 - AD X0RW3 Исключающее ИЛИ над содержимым сло- ва (три операнда) Маска/rw/, исходное поле/rw/, поле ре- зультата/ww/ ♦ ♦ 0 — Приложения
514 Приложения Список команд в порядке возрастания числовых значений их кодов операций 00 HALT 40 ADDF2 80 ADDB2 CO ADDL2 01 NOP 41 ADDF3 81 ADDB3 Ct ADDL3 02 REI 42 SUBF2 82 SUBB2 C2 SUBL2 03 ВРТ 43 SUBF3 83 SUBB3 C3 SUBL3. 04 RET 44 MULF2 84 MULB2 C4 MULL2 05 RSB 45 MULF3 85 MULB3 C5 MULL3 06 LDPCTX 46 DIVF2 86 DIVB2 . C6 DIVL2 07 SVPCTX 47 DIVF3 87 DIVB3 C7 DIVL3 08 CVTPS 48 CVTFB 88 BISB2 C8 BISL2 09 CVTSP 49 CVTFW 89 BISB3 C9 BISL3 ОА INDEX 4A CVTFL 8A BICB2 CA BICL2 ОВ CRC 4B CVTRFL 8B BICB3 CB BICL3 ОС PROBER 4C CVTBF 80 XORB2 CO X0RL2 0D PROBEW 4D CVTWF 8D X0RB3 CD X0RL3 ОБ INSQUE 4E CVTLF 8E MNEGB CE MNEGU OF REMQUE 4F ACBF 8F CASEB CF CASEL 10 BSBB 50 MOVF 90 MOVB DO MOVL 11 BRB 51 CMPF 91 CMPB Dt CMPL 12 BNEQ, BNEQU •52 MNEGF 92 MCOMB D2 MCOML 13 BEQL. BEQLU 53 TSTF 93 BITB D3 BITL . 14 BGTR 54 EMODF 94 CLRB D4 CLRF.CLRL 15 BLEQ 55 POLYF- 95 TSTB D5 TSTL 16 JSB 56 CVTFD 96 INCB D6 INCL 17 JMP 57 зарезервир. 97 'DECB D7 DECL 18 BGEQ 58 ADAWI 98 CVTBL D8 ADWO 19 BLSS 59 Зарезервир. 99 CVTBW D9 SBWG 1А BGTRU 5A зарезервир. 9A MOVZBL DA MTPR 1В BLEQU 5B зарезервир. 9B MOVZBW DB MFPR 1С BVC 5C зарезервир. 9C ROTL DC MOVPSL .1D BVS 5D зарезервир. 9D ACBB DD PUSHL 1Е BCC, BGEQU 5E зарезервир. 9E MOVAB DE MOVAF. MOVAL IF BCS, BLSSU 5F зарезервир. 9F PUSHAB DF PUSHAF. PUSHA 20 ADDP4 60 ADDD2 AO ADDW2 EO BBS 21 ADDP6 61 ADDD3 Al ADDW3 El BBC 22 SUBP4 62 SUBD2 A2 SUBW2 E2 BBSS 23 SUBP6 63 SUBD3 A3 SUBW3 E3 BBCS 24 CVTPT 64 MULD2 A4 MULW2 E4 BBSC 25 MULP 65 MULD3 A5 MULW3 E5 BBCC 26 CVTTP 66 DIVD2 A6 DIVW2 E6 BBSSl 27 DIVP 67 DIVD3 A7 DIVW3 E7 BBCCl 28 M0VC3 68 CVTDB A8 BISW2 E8 BLBS 29 СМРСЗ 69 CVTDW A9 BISW3 E9 BLBG 2A SCANC 6A CVTDL AA BICW2 EA FFS 2B SPANC 6B CVTRDL AB BICW3 EB FFC 2C M0VC5 6C CVTBD AC X0RW2 EC CMPV 2D CMPC5 6D CVTWD 'AD X0RW3 ED CMPZV 2E MOVTC 6E CVTLD AE MNEGW EE EXTV 2F MOVTUC 6F ACBD AF CASEW EF EXTZV 30 BSBW 70 MOVD BO M0VW FG INSV ' 31 BRW 71 CMPD Bl CMPW Ft ACBL 32 CVTWL 72 MNEGD B2 MCOMW F2 AOBLSS 33 CVTWB 73 TSTD B3 BITW F3 AOBLEQ ’34 MOVP 74 EMODD B4 CLRW F4 SOBGEQ 35 СМРРЗ 75 POLYD B5 TSTW F5 SOBGTR 36 CVTPL 76 CVTDF B6 INCW F6 CVTLB 37 CMPP4 77 зарезервир. B7 DECW F7 CVTLW 38 EDITPC 78 ASHL B8 BISPSW F8 ASHP 39 МАТСНС 79 ASHQ B9 BICPSW F9 CVTLP ЗА LOCC 7A EMUL BA POPR FA CALLG ’ЗВ SKPC 7B EDIV BB PUSHR FB CALLS зс MOVZWL 7C CLRD, CLRQ BC CHMK FC XFC 3D ACBW 7D MOVQ BO CHME FD зарезервир. ЗЕ MOVAW 7E MOVAD, MOVAQ BE CHMS FE зарезервир. 3F PUSHAW 7F PUSHAD,PUSHAQ Bf chmu FF эарзэерчир.
Приложения 515 Формат списка параметров команды CALL Список параметров — это последовательность длинных слов, имеющая следующую структуру: 1 п ; Список парамет- ров Параметр 1 Параметр 2. Параметр п Содержимое счетчика параметров п представляет собой це- лое число без знака, занимающее первый (по порядку) байт списка. Старшие 24 разряда первого длинного слова списка за- резервированы для возможного использования в будущем и должны быть заполнены двоичными нулями. При обращении к счетчику параметров вызываемая процедура должна игнориро- вать зарезервированные разряды и извлекать из списка копию содержимого счетчика так, как это делается при выполнении команды MOVZBL. Режимы адресации с использованием регистров общего назначения (РОН) 7 4 3 О Режим . адресации Номер t регистра Байт- спецификатор операнда Режим адресации Запись операнда на языке ассемблера Доступ к операнду PC SP Возможность примене- ния индексирования Код Название шестнадца- теричный десятичный г ш w а V 0-3 0-3 Литеральный S" литерал У f f f f — — f 4 4 Индексный i[Rx] У У У У У f У f 5 5 Регистровый Rn У У У f У u ug f 6 6 Регистровый косвенный (Rn) У У У У У u У У
516 П риложения Режим адресации Запись операнда на языке ассемблера Доступ , к операнду г m w a v PC SP Возможность примене- ния индексирования Код Название шестнадца- теричный десятичный 7 7 Косвенный с авто- уменьшением адреса -(Rn) У У У У У U У их 8 8 Косвенный с увеличе- нием адреса (Rn) + У У У У У р У их 9 9 Двойной косвенный с автоувеличением ад- реса e(Rn) + У У У У У р У их А 10 Относительный «сме- щением к РОН» раз- мером байт B'D(Rn) У У У У У р У У В 11 Относительный косвен- ный «смещением к РОН» размером байт ®B~D(Rn) У У У У У р У У С 12 Относительный «сме- щением к РОН» раз- мером слово W~D(Rn) У У У У У р У У D 13 Относительный косвен- ный «смещением к РОН» размером сло- во ®W~D(Rn) У У У У У р У У Е 14 Относительный «сме- щением к РОН» раз- мером длинное сло- во L~D(Rn) У У У У У р У У F 15 Относительный косвен- ный «смещением к РОН» размером длинное слово ®L~D(Rn) У У У У У р У У
Приложения 517 Режимы адресации с использованием счетчика команд (СК), т. е. регистра R15 о 3_____2 Режим адресации 1111 । ... - 1 । Байт - спецификатор ’оперднЭ^ Режим адресации Запись операнда на языке ассемблера Доступ к операнду г m w a v PC SP Возможность примене- ния индексирования Код Название шестнадца- теричный десятичный 8 8 Непосредственный I "'константа у u и у у — — У 9 9 Абсолютный ©адрес У У У У У — — У А 10 Относительный «сме- щением к СК» раз- мером байт В "'адрес У У У У У — — У В 11 Относительный косвен- ный «смещением к СК» размером байт ©В"'адрес У У У У У — — У С 12 Относительный «сме- щением к СК» раз- мером слово адрес У У У У У — — У D 13 Относительный косвен- ный «смещением к СК» размером слово ©W''адрес У У У У У — — У Е 14 Относительный «сме- щением к СК» раз- мером длинное слово адрес У У У У У — — У F 15 Относительный косвен- ный «смещением к СК» размером длин- ное слово ©L^ адрес У У У У У У
518 Приложения Условные обозначения, используемые при описании режимов адресации Режим доступа к операнду Синтаксические знаки, используемые для указания режима адресации при записи операнда Допустимость применения режимов адресации г = чтение i = любой режим ад- у = применение допустимо, все- гл == модифика- ресации, допускаю- гда является корректным ре- ция щий использование жимом адресации w = запись а = получение адреса индексирования f = зарезервированный режим адресации — «в применение логически не- возможно р = допустима дресация отно- сительная «смещением к СК» v = обращение D — смещение и = результат применения не- к строке би- Rn = РОН с номера- предсказуем тов ми п,= 0—15 Rx = РОН с номерами х = 0—14 uq = результат применения не- предсказуем для целых чисел размером двойное длинное сло- во и чисел с плавающей точкой двойной точности (а также для данных типа «строка битов», если сумма значений парамет- ров этих данных «смещение» и «размер» больше 32) их == результат применения не- предсказуем, если один и тот же регистр используется в ка- честве индексного и базового Примечание: PC — Program Counter (счетчик команд) SP — Stack Pointer (указатель стека) Условные обозначения, используемые при описании операндов команд Стандартная форма описания операнда команды имеет сле- дующий ВИД} / название \ у / спецификатор доступа \операнда//\ к операнду ’ спецификатор типа данных, задаваемых < операндом 1. Название операнда отражает его назначение при выполнении команды, в которой он указывается, Для неявно заданного one-
Приложения 519 ранда в качестве названия используется записываемое пропис- ными символами наименование регистра или ссылка на поле па- мяти. 2. Спецификатор доступа к операнду — это буква, обозначающая способ доступа к указанному операнду, а именно: а — вычисляется действительный адрес заданного операнда; этот адрес помещается в указатель, который и является истин- ным операндом команды; при вычислении адреса учитывается размер поля представления данных, указываемый спецификато- ром тип данных-, b — отсутствует ссылка на операнд; спецификатор операнда задает смещение, определяющее адрес перехода; размер поля смещения определяется спецификатором тип данных; ш — выполняется модификация значения операнда (допусти- мо как чтение содержимого поля, адресуемого операндом, так и запись в это поле); г — выполняется только чтение содержимого поля, адресуе- мого операндом; w — выполняется только запись в поле, адресуемое операн- дом; v — если название операнда задано не в виде Rn, то доступ к операнду осуществляется согласно спецификатору «а»; если название операнда — Rn, то производится обращение к паре смежных регистров R[n-H] и R[n]. 3. Спецификатор типа данных — буква, обозначающая тип дан- ных, задаваемых операндом; b — целое число размером байт; d — число с плавающей точкой двойной точности} f — число с плавающей точкой; 1 — целое число размером длинное слово; q — целое число размером двойное длинное слово; v — поле битов переменной длины (используется только для неявно задаваемых операндов); w — целое число размером слово; х — первый из типов данных, указанных в коде операции команды; у — второй из типов данных, указанных в коде операции команды; * — группа смежных длинных слов используется только для неявно задаваемых операндов. 4. Неявно задаваемые операнды ( т. е. ячейки памяти, к которым производится обращение при выполнении команды, но которые не указываются в операндах команды) обозначаются заключен- ными в квадратные скобки — [ ]. Обозначения, используемые для указания значений битов признака результата:
520 Приложения * присвоение биту признака результат значения 0 или 1 и зави- симости от выполнения условия; — команда не воздействует на значение бита признака резуль- тата; . 0 присвоение биту признака результата значения 0; 1 присвоение биту признака результата значения 1. Примеры записи на языке ассемблера операндов с использованием различных режимов адресации S~#5 константа, задаваемая и представляемая в машине в форме литерала по указанию #5 программиста константа, задаваемая программистом в форме литерала; представление констан- ты в машине — «литеральное» или «не- посредственное» — определяет трансля- тор по критерию минимума размера поля R10 (R10) - (R10) представления регистровая адресация регистровая косвенная адресация косвенная адресация с автоуменьшением (R10) + адреса косвенная адресация с автоувеличением #START адреса константа, задаваемая программистом с помощью непосредственной адресации; представление константы в машине — «непосредственное» или «литеральное» — определяет транслятор по критерию ми- r# 1 нимума размера поля представления константа, задаваемая и представляемая в машине с помощью непосредственной @(R10) + адресации по указанию программиста двойная косвенная адресация с автоуве- личением адреса START 1 (RIO) абсолютная адресация относительная адресация «смещением к РОН»; в программе размер поля пред- ставления смещения указывается равным 1 байт; транслятор выбирает фактиче- ский размер поля представления смеще- ния в машине по критерию минимума ве- 0(R10) личины этого размера регистровая косвенная адресация; размер поля представления операнда в машине
Приложения 521 выбирает транслятор по критерию мини- @1 (RIO) мума величины этого размера косвенная относительная адресация «сме- щением к РОН»; в программе размер по- ля представления смещения указывается равным 1 байт; транслятор выбирает фактический размер поля представления смещения в машине по критерию мини- @(R10) мума величины этого размера косвенная относительная адресация «с подразумеваемым смещением к РОН»; размер поля представления явно не ука- зываемого в команде смещения, равен 1 байт START относительная адресация «смещением к СК»; транслятор выбирает размер поля представления смещения в машине по критерию минимума величины этого раз- ©START мера косвенная относительная адресация «сме- щением к СК»; транслятор выбирает раз- мер поля представления смещения в ма- шине по критерию минимума величины 1234 (RIO) этого размера относительная адресация «смещением к РОН»; в программе размер поля пред- ставления смещения указывается равным 1 слово; транслятор выбирает фактиче- ский размер поля представления смеще- ния в машине по критерию минимума ве- @1234 (RIO) личины этого размера косвенная относительная адресация «сме- щением к РОН»; в программе размер по- ля представления смещения задается равным 1 слово; транслятор выбирает фактический размер поля представления смещения в машине по критерию мини- 12345678 (RIO) мума величины этого размера относительная адресация «смещением к РОН»; размер поля представления сме- щения равен 1 длинное слово @12345678 (RIO) косвенная относительная адресация «сме- щением к РОН»; размер поля представ- B~ 12 (RIO) ления смещения равен длинному слову относительная адресация «смещением к РОН»; в программе размер поля пред-
622 Приложения ставления смещения задается равным 1 байт; в машине смещению предостав- B~START ляется поле размером 1 байт относительная адресация «смещением к СК»; в программе размер поля представ- ления смещения задается равным 1 байт; в машине смещению предоставляется по- ©В"" 12 (RIO) ле размером 1 байт косвенная относительная адресация «сме- щением к РОН»; в программе размер по- ля представления смещения задается рав- ным 1 байт, в машине смещению предо- @B~START ставляется поле размером 1 байт косвенная -относительная адресация «смещением к СК»; в программе размер поля представления смещения задается равным 1 байт; в машине смещению пре- доставляется поле размером 1 байт W" 12 (RIO) относительная адресация «смещением к РОН»; в программе размер поля пред- ставления смещения задается равным 1 слово; в машине смещению предостав- ляется поле размером 1 слово W" START относительная адресация «смещением к СК»; в программе размер поля представ- ления смещения задается равным 1 сло- во; в машине смещению предоставляется ©W''12 (RIO) поле размером 1 слово косвенная относительная адресация «сме- щением к РОН»; в программе размер по- ля представления смещения задается рав- ным 1 слово; в машине смещению предо- @W~ START ставляется поле размером 1 слово косвенная относительная адресация «сме- щением к СК»; в программе размер поля представления смещения задается рав- ным 1 слово; в машине смещению предо- IT 12 (RIO) ставляется поле размером 1 слово относительная адресация «смещением к РОН»; в программе размер поля пред- ставления смещения задается равным 1 длинное слово; в машине смещению предоставляется поле размером 1 длин- ное слово L'START относительная адресация «смещением к СК»; в программе размер поля представ-
Приложения 523 ления смещения задается равным 1 длин- ное слово; в машине смещению предостав- ляется поле размером 1 длинное слово @L^12(R10) косвенная относительная адресация «сме- щением к РОН»; в программе размер по- ля представления смещения задается равным 1 длинное слово; смещению пре- доставляется поле размером 1 длинное слово @L~START косвенная относительная адресация «сме- щением к СК»; в программе размер поля представления смещения задается рав- ным 1 длинное слово; в машине смеще- нию предоставляется поле размером 1 длинное слово (R10HRU] регистровая косвенная адресация с ин- — (R1O)[R11] дексированием косвенная адресация с автоуменьшением (RIO) + [Rll] адреса с индексированием косвенная адресация с автоувеличением @(R10) + [Rll] адреса с индексированием двойная косвенная адресация с автоуве- личением адреса с индексированием START [Rll] абсолютная адресация с использованием индексирования 1 (RIO) [Rll] относительная адресация «смещением к РОН» с индексированием; в программе размер поля представления смещения указывается равным 1 байт; транслятор выбирает фактический размер поля пред- ставления смещения по критерию мини- мума величины этого размера 0 (RIO) [Rll] регистровая косвенная адресация с ин- дексированием; размер поля представле- ния операнда в машине выбирает транс- лятор по критерию минимума величины этого размера @1 (RIO) [Rll] косвенная относительная адресация «сме- щением к РОН» с индексированием; в программе размер поля представления смещения указывается равным 1 байт; транслятор выбирает фактический раз- мер поля представления смещения в ма- шине по критерию минимума величины этого размера
524 Приложения @ (RIO) [Rll] косвенная относительная адресация «с подразумеваемым смещением к РОН» с индексированием; размер поля представ- ления явно не указываемого в команде смещения равен 1 байт 1234 (RIO) [Rl 1] относительная адресация «смещением к РОН» с индексированием; в программе размер поля представления смещения указывается равным 1 слово; транслятор выбирает фактический размер поля пред- ставления смещения в машине по крите- рию минимума величины этого размера @1234 (RIO) [Rl 1] косвенная относительная адресация «сме- щением к РОН» с индексированием; в программе размер поля представления смещения задается равным 1 слово, транслятор выбирает фактический раз- мер поля представления смещения в ма- шине по критерию минимума величины этого размера 12345678 (RIO) [Rll] относительная адресация «смещением к РОН» с индексированием; размер поля представления смещения равен 1 длинное слово @12345678 (RIO) [Rll] косвенная относительная адресация «сме- щением к РОН» с индексированием; раз- мер поля представления смещения равен 1 длинное слово START [Rll] относительная адресация «смещением к СК» с индексированием; транслятор вы- бирает размер поля представления сме- щения в машине по критерию минимума величины этого размера @START[R11] косвенная относительная адресация «сме- щением к СК» с индексированием; транс- лятор выбирает размер поля представле- ния смещения в машине по критерию ми- B" 12 (RIO) [RU] нимума величины этого размера относительная адресация «смещением к РОН» с индексированием; в программе размер поля представления смещения за- дается равным 1 байт; в машине смеще- нию предоставляется поле размером 1 байт В''START [Rll] относительная адресация «смещением к СК» с индексированием; в программе
Приложения 525 размер поля представления смещения за- дается равным 1 байт; в машине смеще- нию предоставляется поле размером 1 байт @B~12(R1O)[R11] косвенная относительная адресация «сме- щением к РОН» с индексированием; в программе размер поля представления смещения задается равным 1 байт; в ма- шине смещению предоставляется поле @В"START [Rll] размером 1 байт косвенная относительная адресация «сме- щением к СК» с индексированием; в про- грамме размер поля представления зада- ется равным 1 байт; в машине смещению предоставляется поле размером 1 байт W' 12(RIO) [Rll] относительная адресация «смещением к РОН» с индексированием; в программе размер поля представления смещения за- дается равным 1 слово; в машине сме- щению предоставляется поле размером 1 слово W~START[R11] относительная адресация «смещением к СК» с индексированием; в программе размер поля представления смещения за- дается равным 1 слово; в машине сме- щению предоставляется поле размером 1 слово @W~12(R10) [Rll] косвенная относительная адресация «сме- щением к РОН» с индексированием; в программе размер поля представления смещения задается равным 1 слово; в ма- шине смещению предоставляется поле размером 1 слово @W~START [Rl 1] косвенная относительная адресация «сме- щением к СК» с индексированием; в про- грамме размер поля представления сме- щения задается равным 1 слово; в маши- не смещению предоставляется поле раз- мером 1 слово L~12 (RIO) [Rll] относительная адресация «смещением к РОН» с индексированием; в программе размер поля представления смещения за- дается равным 1 длинное слово; в маши- не смещению предоставляется поле раз- мером 1 длинное слово
526 Приложения L "START [Rll] @L"12(R10) [Rll] @L" START [Rll] относительная адресация «смещением к СК» с индексированием; в программе размер поля представления смещения за- дается равным 1 длинное слово; в маши- не смещению предоставляется поле раз- мером 1 длинное слово косвенная относительная адресация «сме- щением к РОН» с индексированием; в программе размер поля представления смещения задается равным 1 длинное слово; в машине смещению предоставля- ется поле размером 1 длинное слово косвенная относительная адресация «сме- щением к СК» с индексированием; в про- грамме размер поля представления сме- щения задается равным 1 длинное слово; в машине смещению предоставляется по- ле размером 1 длинное слово ЗГ 30 2928 2726 2524 232221 20 56 15 Длинное слово состояния процессора 2 Слово состояния программы * I « 1 I 1 1_I 1 I Г I I I__]_1 1... уровень приоритета запроса на прерывания предшествующий режим доступа текущий режим доступа работа со стеком прерываний завершение первой части цикла выпол- нения машинной команды задержка трассировки прерываний режим совместимости Слово состояния программы 15______878 5 43210 не используется ( । । । 1 1 1 бит разрешения прерывания при ____г переполнении, возникающем пру вы-^ полпенни операции десятичной арифметики бит разрешения прерывания при потере — значимости, возникающей при выполнении операций изо числами с плавающей точкой бит разрешения прерывания при перепои не- — нии, возникающим при выполнении операции знаЦимдсти. возйикающей при выполнении операций изо числами с плавающей точкой нии, возникающем при над целыми числами бит разрешения трассировки прерываний биты Г отрицательный-------------------- признака J нулевой --------------------- пр^ппкгпягтш 1 переполнение------------ результата перенос ...........— —
Приложения 527 Число 2 в степени п Число 16 в степени п 2П п 16* п 256 8 1 0 512 9 16 1 1024 10 256 2 2048 11 4096 3 4096 12 65536 4 8192 13 1048576 5 16384 14 16777216 В 32768 15 268435456 7 65536 16 4294967296 8 131072 17 68719476736 9 262144 18 1099511627776 10 524288 19 17592186044416 11 1048576 2Q 281474976710656 12 2097152 21 4503599627370496 13 4194304 22 72057594037927936 14 8388608 23 1152921504606646976 15 16777216 24
528 Приложения Типы данных Целое число размером байт Целое число размером слово Строка символов _ и строка цифр (числовая * строка) Строка апакд* ванных десягпИЧ* W цифр
Предметный указатель Адрес базовый 390 — действительный 84 — относительный 83 Адресация двухуровневая косвенная 242 — косвенная 224 — косвенная с автоувеличением ад- реса 242 — косвенная с автоуменьшением ад- дреса 242 — косвенная регистровая двойная 242 — косвенная регистровая 225 — с автоувеличением адреса 228 — с автоуменьшением адреса 228 — смещением к РОН 236 — смещением к СК 83 Аккумулятор 13 Ассемблер 31 Бит-индикатор признака результата 115 Блок вызова 304 — RAB 416 — FAB 416 Блокировка доступа к памяти 448 Буферизация 419 Вызов по дескриптору 303 — по имени 302 — по значению 302 Деассемблирование 154 Директива 33 Дополнение 403 Запись 414 — порядка с «избытков 128» 354 Имя символическое глобальное 320 Инверсия поразрядная 68 Индекс элемента массива 216 Индексирование 198 Интерпретатор 31 Код дополнительный 68 — обратный 68 — операции 15 — режима адресации 82 Компилятор 31 Константа именуемая 186 Макрокоманда 91, 327 Макроопределение 327 Макрорасширение 328 Маска входа 304 — регистров 294 Метка локальная 336, 439 Модуль объектный 98. — реентерабельный 320 Обработка особых ситуаций 305 Операнд 15 Операнд-выражение 182 Оператор присваивания 186 Операции асинхронные логические 402 — над битами 390 — над записями 419 • — над файлами 416 — синхронные 415 Организация файлов индексная 415 — относительная 415 — последовательная 415 Отладчик 144 Очередь 434 Псевдокод 20 Редактирование связей 98 Регистр индексный 205 — команд 13 — общего назначения 77
530 Предметный указатель Сдвиг 400 — циклический 402 Сеанс отладки 154 Система счисления 52 Слово состояния программы 78 ---процессора 78 Смещение 409 Стек 289 Стоп-символ 279 Строка битов 390 — символов 254 — числовая с ведомым знаком 372 — числовая с раздельным ведущим знаком 372 Счетчик адреса 106 — команд 13 Субрутина 295 Точка наблюдения за состоянием данных 149 — останова 145 — трассировки 149 Таблица символических имен 106 — трансляции кодов 276 Трансляция по условию 343 Указатель блока вызова 77 — стека 77, 290 Условие составное 297 Файл 414
Оглавление Предисловие редактора перевода................................... 5 Предисловие автора.................................................7 Глава 1. Вычислительные машины простой архитектуры.............12 1.1. Обобщенная структура TOYCOM..........................13 1.2« Машинные команды.....................................15 1,3. Выполнение программы, хранимой в памяти , . « • > 15 1.4. Набор команд TOYCOM..................................17 1.5« Функционирование машины: цикл извлечения и выполнения команды....................................................23 1.6. Принятие решения при альтернативных возможностях выпол- нения программы............................................23 1.7. Недостатки программирования в машинных кодах.........29 1.8. Язык ассемблера TOYCOM...............................30 1.8.1, Трансляторы..........................................30 1.8.2. Выполняемые команды...................................>33 1.8.3. Директивы транслятора..................................33 1.8.4, Программа на языке TOYCODE...........................35 1.9. Перевод программы с псевдокода на язык TOYCODE ... 36 1.9.1. Преобразование оператора цикла WHILE.................36 1.9.2. Преобразование оператора выбора IF...................39 1.10. Примеры программ на языке TOYCODE.....................40 Выводы ............................................................47 Вопросы и упражнения...........................................49 Глава 2. Арифметика недесятичных чисел • ...................52 2.L Позиционные системы счисления..........................53 2.2. Двоичные и шестнадцатеричные системы счисления .... 53 2.3. Сложение и вычитание чисел...........................56 2.3.1. Сложение ...............................................56 2.3.2. Вычитание ............................................ 60 2.4. Преобразование чисел при переходе из одной системы счисле- ния в другую............................................63 2.4.1, Представление чисел в десятичной системе счисления .... 63 2.4.2. Преобразование двоичных чисел в шестнадцатеричные и шест- надцатеричных чисел в двоичные................................65 2.4.3. Преобразование чисел в недесятичные системы счисления . . 66 2.5. Представление отрицательных чисел в дополнительном коде 68 Выводы ............................................................71 Вопросы и упражнения , ............................................71
532 Оглавление Глава 3. Введение в архитектуру и язык ассемблера системы VAX . . 73 3.1. Введение в архитектуру системы VAX...................73 3.2. Команды арифметики целых чисел размером длинное слово . 78 3.2.1. Символическая адресация и способы выделения памяти ... 78 3.2.2. Форматы простых машинных команд......................81 3.2.3. Команды пересылки....................................85 3.2.4. Команды арифметических операций......................86 3.2.5. Пример фрагмента программы...........................88 3.2.6. Использование констант в качестве операндов..........89 3.2.7. Команды ввода и вывода...............................91 3.3. Выполнение программ, написанных на языке ассемблера . . 92 3.3.1. Директивы .PSECT, .ALIGN, .ENTRY и .END..............93 3.3.2. Создание исходного текста программы. Трансляция, редактиро- вание и выполнение.............................................97 3.4. Ошибки при выполнении программы.........................104 3.5. Трансляция программы ...................................106 Выводы ........................................................109 Вопросы и упражнения..............................................111 Глава 4. Программирование ветвящихся и циклических вычислительных процессов на языке ассемблера...................................114 4.1. Команды условной и безусловной передачи управления. . . 114 4.2. Циклы с предварительной проверкой условия..................120 4.3. Ветвящиеся вычислительные процессы *.......................124 4.4. Циклы, управляемые счетчиком...............................129 4.5. Дополнительные команды организации циклов..................137 4.6. Директивы транслятора .TITLE, .SUBTITLE и .PAGE .... 138 Выводы ...........................................................139 Вопросы и упражнения.............................................140 Глава 5. Отладчик операционной системы VAX/VMS..................144 5.1. Обобщенная характеристика отладчика.....................144 5.2. Точки останова, трассировки и наблюдения за состоянием дан- ных ....................................................... .145 5.2.1. Точки останова.........................................145 5.2.2. Точки трассировки......................................147 5.2.3. Точки наблюдения за состоянием данных ....................149 5.3. Выполнение протраммы под управлением отладчика..........150 5.4. Команды EXAMINE и DEPOSIT...............................153 5.5. Вызов отладчика и выход из него....................... . . 157 5.5.1. Изменение значений параметров, принимаемых по умолчанию . 158 5.5.2. Параметр DO команды установки точек останова...........159 5.6. Пример сеанса отладки . <................................160 5.7. Команда DUMP...............................................168 Выводы ..............................................................168 Вопросы и упражнения.................................................170 Глава 6. Целые числа различных разглсроз с .........................172 6.1. Форматы представления целых чисел........................172 6.1.1. Директивы для работы с целыми числами, размер которых не равен длинному слову................................... ...... 173
Оглавление ваз 6.1.2. Команды пересылки и выполнения арифметических операций над целыми числами, размер которых не равен длинному слову 174 6.1.3. Команды преобразования форматов данных f ...... . 180 6.1.4. Отладчик и целые числа, размер которых не равен длинному слову.....................................................181 6.1.5. Ввод и вывод целых чисел, размер которых не равен длин- ному слову 182 6.2. Операнды-выражения..........................................182 6.3. Запись констант в системах счисления, отличных от десятичной 185 6.4. Оператор присваивания.......................................186 6.5. Пример программы............................................187 6.6. Признаки переполнения и переноса............................190 Выводы ................................................................ЮЗ Вопросы и упражнения..................................................196 Глава 7. Массивы и индексирование...................................199 7.1. Назначение массивов.....................................199 7.2. Принципы индексирования ..............................201 7.3. Индексирование в системе VAX............................202 7.3.1. Синтаксис индексирования на языке ассемблера...........203 7.3.2, Операция индексирования................................206 7.4. Команда INDEX...........................................216 7.5. Матрицы ............................................... 217 Выводы ..........................................................220 Вопросы и упражнения ............................................221 Глава 8. Косвенная адресация.......................................224 8.1. Принципы косвенной адресации....................... ..... 224 8.2. Регистровая косвенная адресация...........................225 8.3. Косвенная адресация с автоматическим увеличением или умень- шением адреса.................................................228 8.4. Режим адресации с использованием смещения.................235 8.5. Относительная косвенная адресация...................... . 235 8.6. Двухуровневая косвенная адресация.........................242 8.7. Управление размером смещения . . ......................247 Выводы ............................................................248 Вопросы и упражнения...............................................250 Глава 9. Обработка символьных данных . ................254 9.1. Кодирование символов и символьные данные.......254 9.2. Ввод и вывод символьных данных.................258 9.3. Обработка символьных данных.................... 260 9.3.1. Сортировка символьных данных.................260 9.3.2. Поиск слов в тексте . . , •.............. 271 9.3.3. Поиск в строке подстрок......................280 Выводы ...............................................285 Вопросы и упражнения...................................286
534 Оглавление Глава 10. Подпрограммы .........................................289 10.1. Операции со стеком....................................289 10.2. Простые подпрограммы . . . ........................295 10.3. Передача фактических параметров через общий список фор- мальных параметров...........................................302 10.4. Передача фактических параметров через стек............310 10.5. Рекурсивные процедуры.................................313 10.6. Библиотеки подпрограмм ..........................320 10.7. Подпрограммы и программа отладки......................321 Выводы ......................................................322 Вопросы и упражнения.........................................323 Глава 11. Макрокоманды • ••«.....................................327 11.1. Определение понятия «макрокоманда» ......................327 11.2. Макрокоманды без параметров............................328 11.3. Передача параметров макроопределению...................331 11.3.1. Простые параметры макрокоманд .......... 331 11.3.2. Параметры, задаваемые по умолчанию...................332 11.3.3. Ключевые параметры...................................333 11.3.4. Параметры в виде строк символов......................334 11.3.5. Сцепление параметров.................................324 11.3.6. Формирование уникальных символических имен...........335 11.4. Операции над строками символов.........................337 11.5. Циклы на этапе трансляции и трансляция по условию .... 339 11.5.1. Циклы .................................................339 11.5.2. Символические имена как параметры и их значения .... . 340 11.5.3. Циклы со списком значений параметра . . ...............341 11.5.4. Трансляция по условию..................................343 11.6. Прочие директивы.........................................345 11.7, Управление включением макрорасширения в листинг трансля- ции .........................................................347 Выводы ............................................................348 Вопросы и упражнения...............................................349 Глава 12. Команды десятичной арифметики и арифметики чисел с плаваю- щей точкой.............................................352 12.1. Числа с плавающей точкой одинарной точности..........352 12.1.1. Запись числа с плавающей точкой одинарной точности . . . 352 12.1.2. Запись констант в форме с. плавающей точкой........356 12.1.3. Неарифметические операции над числами с плавающей точкой 357 12.1.4. Арифметические команды чисел с плавающей точкой .... 358 12.2. Числа с плавающей точкой двойной точности............369 12.3. Операции над десятичными числами..........................371 12.3.1. Форматы десятичных данных................................371 12.3.2. Команды десятичной арифметики............................374 12.3.3. Команды преобразования десятичных данных.................378 Выводы ,.......................................................385 Вопросы и упражнения...........................................387 Глава 13. Операции над битами и логические операции............390 13.1. Данные в виде строки битов...........................390 13,2. Операции над строками битов ...............................391
Оглавление 535 13.3. Команды сдвига........................................400 13.4. Логические операции...................................402 Выводы .................................................409 Вопросы и упражнения............................................410 Глава 14. Средства ввода и вывода . ......................414 14.1. Обзор возможностей подсистемы RMS.....................414 14.2. Блоки управления......................................416 14.2.1. Резервирование памяти для блоков управления.........416 14.2.2. Операции над файлами................................418 14.2.3. Операции над записями ..............................419 14.3. Примеры программ......................................421 14.4. Операции ввода и вывода на терминал...................427 Выводы .................................................430 Вопросы и упражнения............................................432 Глава 15. Остальные команды системы VAX • • ...................434 15.1. Очереди...............» ...... .....................434 15.2. Локальные метки...................................* . 439 15.3. Структуры выбора направления хода вычислений...440 15.4. Команды арифметики целых чисел с повышенной точностью . 442 15.5. Перекодирование символов..............................444 15.6. Команда EDITPC..............*.........................447 15.7. Блокировка доступа к памяти...........................443 15.8. Дополнительные команды системы VAX....................440 15.8.1. Команды, доступные пользователям....................449 15.8.2. Привилегированные команды...........................453 Выводы .........................................................454 Вопросы и упражнения . .........................................455 Приложение А. Эмулятор вычислительной машины TOYCOM , . ... 457 Приложение Б. Таблица преобразования десятичных чисел в шестнадцате- ричные и обратно , .............................................460 Приложение В. Код ASCII * . , , ................................461 Приложение Г. Макрокоманды ввода — вывода и стандартные подпро- граммы t . . . .................................................462 Приложение Д. Ответы на некоторые задачи........................485 Приложение Е. Набор команд системы VAX..........................492 Предметный указатель ...........................................529
УВАЖАЕМЫЙ ЧИТАТЕЛЬ! Ваши замечания о содержании книги, ее оформ- лении, качестве перевода и другие просим присылать по адресу: 129820, Москва, И-110, ГСП, 1-й Рижский пер., д. 2, изд-во «Мир». монография Роберт Сибеста СТРУКТУРНОЕ ПРОГРАММИРОВАНИЕ НА ЯЗЫКЕ АССЕМБЛЕРА ЭВМ VAX-11 Старший научный редактор Т. Н. Шестакова Младший редактор Т. Б. Вахнюк Художник А. С. Шумилин Художественный редактор Н. М. Иванов Технический редактор Н. И. Манохина Корректор А, Ф. Рыбальченко ИБ № 6025 Сдано в набор 18.02.87. Подписано к печати 03.09.87. Формат бОХЭО'Ав. Бумага кн.-журн. сыкт. Печать высокая. Гарниту- ра литературная. Объем 16,75 бум. л. Усл. печ. л. 33,5. Усл. кр.-отт. 34. Уч.-изд. л. 30,1. Изд. №6/4648. Тираж 50000 экз. Зак. 483. Цена 2 р. 40 к. ИЗДАТЕЛЬСТВО «МИР» 129820, ГСП. Москва, И-110, 1-й Рижский пер., 2 Ленинградская типография № 2 головное предприятие орде- на Трудового Красного Знамени Ленинградского объедине- ния «Техническая книга» им. Евгении Соколовой Союзпо- лиграфпрома при Государственном комитете СССР по делам издательств, полиграфии и книжной торговли. 198052, г. Ле- нинград, Л-52, Измайловский проспект, 29,

2 р. 40 к.