Call VvodMas ;ввод массива A 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Call VvodMas ;ввод массива A



Практическая работа №5.

Тема: Функции BIOS и DOS для работы с экраном и клавиатурой, использование подпрограмм.

Материалы и оборудование: листы бумаги А4 или тетрадные, авторучка, персональная ЭВМ с установленным отладчиком «Insight», файловым менеджером (Far, NC, Windows Commander и т.п.), компилятором и компоновщиком Ассемблера версии «Турбо- ассемблер 2.0» (tasm.exe, tlink.exe).

 

Цель работы – научиться разработке простейших модульных и интерактивных программ на языке Ассемблера.

 

Выполнение задания

1) Разработать алгоритм решения задачи с использованием модульного программирования.

 

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

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

В данном случае есть два подхода к технологии программирования – нисходящее и восходящее проектирование – при первом подходе сначала составляется общий алгоритм, при этом подпрограммы рассматриваются как «черный ящик», то есть известны данные на входе и на выходе, но неизвестен алгоритм их преобразования. Затем последовательно («сверху-вниз») разрабатываются алгоритмы отдельных модулей. При восходящем проектировании процесс производится в обратном порядке. При структурном программировании (основная технология, применяемая при процедурном программировании, по сути предшественница, но до сих пор актуальная, наиболее популярной в настоящее время технологии объектно-ориентированного программирования).

Состав модулей при модульном программировании отображается на схеме иерархии модулей. Рекомендуется строгая иерархия, то есть чтобы модули не вызывали друг друга на одном уровне иерархии и не «перескакивали» через уровень.

Типичная схема иерархии модулей выглядит следующим образом:

Пример: Вычислить выражение: . Исходными данными служит n и массивы a,b. Использовать подпрограмму вычисления квадрата числа. Исходные данные должны вводиться вручную, а ответ выводиться на экран. Необходимо учитывать возможность переполнения и выдавать в этом случае соответствующее предупреждение.

 

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

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

Алгоритм основной программы:

 

В блок-схеме вызов подпрограммы при этом обозначается прямоугольником с двумя дополнительными линиями по краям. После этого разрабатываются алгоритмы подпрограмм. На блок-схемах алгоритмов подпрограмм вместо слов «начало» и «конец» используются «вход» и «выход». Например, блок-схема алгоритма подпрограммы «ввод массива»:

 

Строгое неравенство здесь обусловлено тем, что индексы в массиве начинаются с 0, соответственно в массиве из 5 элементов последний элемент будет с индексом 4.

И так далее. Не всегда обязательно описывать алгоритм каждого модуля именно блок-схемой, в ряде случаев может быть достаточно словесного описания или описания на языке программирования. Например, возведение числа в квадрат блок-схемой описывать не обязательно, куда понятнее просто команда imul ax. Чем сложнее алгоритм, тем более он нуждается в интуитивно более понятном, по исследованиям психологов, графическом описании.

 

2) Закодировать алгоритм с использованием подпрограмм на языке ассемблера и с использованием ввода-вывода.

 

Процедуры в языке ассемблера следующим способом:

 

<идентификатор> proc

….

<идентификатор> endp

 

Команды вызова – CALL

Команда возврата – RET

 

Например:

CALL VVOD

CALL RASCHET

CALL VYVOD

RET (Возврат из главной программы)

 

VVOD PROC

….

RET

VVOD ENDP

………

 

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

CALL VVOD

 

VVOD:

ret)

Точно также и любые данные могут быть интерпретированы процессором как команда и любая команда (её машинный код) может быть использована процессором как данные. Например:

Db 0B8h,0,0 эквивалентна команде mov ax,0 и наоборот. Такой принцип, вытекающий из архитектуры Фон-Неймана (архитектуры вычислительной системы, при которой для команд и для данных используется общая память), предоставляет программисту на ассемблере уникальные преимущества по сравнению с языками высокого уровня – например, программа может модифицировать себя в процессе выполнения.

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

AA PROC

PUSH AX

PUSH BX

POP BX

POP AX

RET

AA ENDP

 

Форматы команды CALL аналогичны форматам команды JMP.

Команда CALL выполняется следующим образом – в стек записывается адрес возврата (следующей за CALL команды), после чего происходит передача управления (JMP).

Команда RET «достает» из стека сохраненные значения, за счет чего происходит возврат в основную программу и реализуется. Благодаря свойству стека «последний пришел первый ушел» (LIFO) реализуется вложенность подпрограмм и возможность рекурсии (вызова подпрограммой самой себя, рекурсия например может быть использована при вычислении факториала числа). Однако следует помнить, что стек не должен измениться при вызове подпрограммы (то есть количество команд push и pop внутри подпрограммы должно быть одинаковым), иначе команда ret вернет управление совсем не в то место программы, откуда подпрограмма была вызвана.

 

После описания алгоритма необходимо определить соглашение о параметрах на входе и на выходе из процедуры – то есть что и где передается модулю, и что и где он возвращает. Механизмы передачи параметров модулям в языке ассемблера могут быть – через глобальные переменные (то есть общие для всех процедур), через регистры, через стек. В ассемблере переменные не разделяются на локальные и глобальные средствами языка. Передача параметров через стек обычно осуществляется при компиляции программ с языков высокого уровня (Паскаль, Си и т.д.). Наиболее простым решением является передача параметров через регистры.

Состав входных и выходных параметров может быть изображен в виде HIPO-диаграммы (см. практическую работу №2). Или описан в виде таблицы, или представлен непосредственно в программе в виде комментариев (для простых программ). Если подпрограмма изменяет содержимое каких-нибудь других регистров (не связанных с входными и выходными данными), об этом необходимо также упомянуть в составе выходных параметров.

При определении параметров необходимо уже представлять себе используемые в программе команды. Например, адрес памяти должен обязательно передаваться в регистрах, по которым можно адресовать память, если предполагается использовать строковые команды – то надо использовать регистры SI DI, для организации цикла – регистр СХ и т.п.

 

Для нашего примера:

Модуль Входные параметры Выходные параметры
Ввод массива VvodMas DI – адрес массива, который необходимо ввести   По адресу DI – введенный массив; DI изменяется
Суммирование квадратов элементов массива SumMas SI – адрес суммируемого массива   AX – сумма квадратов массива
Вывод числа Vyvod   AX – число Нет (число выводится на экран)
Ввод числа Vvod   DX – адрес буфера для вида числа   По адресу DX – строка, содержащая число (в формате функции 0Ah ДОС)
Преобразование во внутренний формат ConvAb   DX– адрес строки с символьным представлением числа (в формате функции 0Ah ДОС) AL – внутреннее представление числа
Вычисление квадрата Sqrr AL – число AX – квадрат числа

 

Затем, когда разработаны алгоритмы процедур, начинаем кодировать их на языке ассемблера, как делали в предыдущих практических работах. Для того, чтобы закодировать вызов подпрограммы, поступаем следующим образом – сначала записываем нужные параметры (входные для неё) в регистры, затем вызываем подпрограмму командой CALL. В самой подпрограмме перед выходом запишем в нужные регистры результаты её работы (сформируем выходные параметры). Естественно, регистры, в которых подпрограмма возвращает результат, сохранять в стеке не надо, иначе никакого результата возвращено не будет. В частности, основная программа будет выглядеть так:

 

Основная программа:

Model tiny

Code

Org 100h

N equ 5

start:

Mov di,offset A

Mov di,offset B

Call SumMas

Call SumMas

Call vyvod

Ret

VvodMas proc

Ret

VvodMas endp

SumMas proc

Ret

Summas endp

Vyvod proc

Ret

Vyvod endp

Vvod proc

Ret

Vvod endp

Convab proc

Ret

Convab endp

A db N dup (?)

B db N dup (?)

End start

Директива компилятора EQU обозначает установку константы – символ N будет заменен ассемблером при компиляции на цифру 5. Это компромиссный вариант, позволяющий избежать сложности с обработкой массивов произвольного размера и вместе с тем позволяющий исправить лишь один символ в ней при необходимости изменить её для обработки массивов других размерностей.

Остальные процедуры пока не описаны. Затем последовательно приступаем к кодированию остальных процедур.

Для того, чтобы программа была интерактивной, то есть осуществляла взаимодействие с пользователем, необходимо организовывать ввод данных с клавиатуры и вывод на экран. Непосредственно работая с ними, как с аппаратными устройствами, это было бы сделать затруднительно – во-первых, разные модели данного периферийного оборудования могут иметь различные версии схем и соответственно интерфейса (соглашения об обмене данными), во-вторых, получались бы довольно громоздкие программы (например, монитора управляется своим контроллером, встроенным в видеоадаптер и имеющим свой процессор и т.д.). Для того, чтобы эффективно работать с периферийным оборудованием, эти функции в основном осуществляются вызовами функций операционных систем – дисковой (DOS) и записанной в постоянной памяти (ПЗУ) компьютера (микропроцессорного устройства) - BIOS. Вызов этих функций осуществляется как вызов некоей подпрограммы, которой передаются параметры (что вывести и куда, или откуда ввести и как). Данная программа операционной системы выполняет требуемые действия и возвращает управление пользовательской программе. В компьютерах на базе микропроцессоров семейства Intel8086 обычно реализуется этот вызов с помощью вызова программного прерывания (будут рассмотрены нами в 7-й работе). Правда, в операционных системах Windows используется обычная команда CALL.

Функции операционной системы вызываются следующим образом – в AH записывается номер функции, в другие регистры – необходимые параметры (определяется типом функции), после чего вызывается операционная система командой INT <номер прерывания>. Наиболее часто используются следующие номера прерываний:

INT 21h – вызов функций DOS

INT 16h – вызов функций BIOS для работы с клавиатурой

INT 10h – вызов функций BIOS для работы с экраном

INT 1Ah – вызов функций BIOS для работы с таймером.

 

Mov ah,01

Int 21h; ввод

Cmp al,’0’

Jl nov_vvod

Cmp al,’9’

Jg nov_vvod

Mov [bx],al

Inc bx

Jmp nov_vvod

…….

String db 10 dup (?)

Помимо ввода/вывода с клавиатуры программа также может получать данные с командной строки. То, что указывается после имени программы при её запуске, называется параметрами командной строки (они разделяются пробелами). В частности, при использовании нами Tlink.exe параметры командной строки – lab3.obj и /t. Командная строка при запуске программы расположена по адресу DS:0080h в формате Длина строки, строка, заканчивающаяся кодом 0Dh.

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

Print macro x

Mov dx,offset x

Mov ah,09

Int 21h

Endm

Описание макрокоманды делается вначале (после org 100h и перед start:).

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

 

Mov ah,09h Mov dx,offset msg1 -> Int 21h     Print msg1

Сам машинный код от этого не изменится, просто сократится время набирания программы. Компилятор ассемблера, встретив в тексте Print заменит его на последовательность 3-х команд, описанных в макросе, а «х» (параметр макрокоманды в описании) заменит на msg1.

Работа с экраном.

Экран (дисплей) с точки зрения программиста на ассемблере – тоже массив цифровой информации. Этот массив хранится в специальной области памяти, называемой видеопамять. Содержимое «текстовой» видеопамяти (то есть отображение экрана в текстовом режиме) начинается с адреса B800:0000, графической A000:0000. Видеоадаптер считывает данные области памяти и отображает на экране информацию в соответствии с режимом работы (текстовым или графическим).

Экран для программиста как бы состоит из отдельных ячеек, которые имеют свои координаты, отсчитываемые по горизонтали и вертикали (столбцы и строки). Координаты начинаются с 0. В текстовом режиме в ячейке может быть записан какой-либо символ, всего таких ячеек в зависимости от режима либо 80х25, либо 40х25 (столбцов х строк) в зависимости от режима экрана. В графическом режиме – точка (пиксель), которых опять же в зависимости от режима может быть от 320х200 до 1024х768 и более (по горизонтали х по вертикали).

В текстовой видеопамяти за каждую «ячейку» отвечают 2 байта – в первом содержится ASCII-код символа, во второй – байт атрибутов. Байт атрибутов определяет цвет символа и фона. Соответственно по адресу B800:0000 находится ASCII-код первого символа (в верхнем левом углу), B800:0001 – цвет его и фона, B800:0002 – второй символ и т.д.

Байт атрибутов организован следующим образом –

 

Бит интенсивности отвечает за яркость символа (1 – яркий), признак мерцания (1 – символ мерцает на экране). Биты R – red – красный, G – green – зеленый, B – blue – синий отвечают за соответствующие цвета. С помощью их комбинаций (как и в фотографии, где изображение формируется из трех основных цветов) и определяется цвета символа и фона. Например, 001 –синий, 010 – зеленый, 100 – красный, 011 – желтый и т.п.

В графической видеопамяти каждый байт (для режимов с количеством цветов до 16, иначе используются несколько байт) отвечает за отдельный пиксель и обозначает его цвет – адресу A000:0000 соответствует цвет точки с координатами (0,0) – левый верхний угол экрана, A000:0001 – точке с координатами (0,1) и т.д.

 

 

Установка видеорежима

VvodMas proc

Push cx;сохраним регистры

Push si

Mov cx,N

Vm1: call vvod

Call ConvAb

Stosb; запомним в массиве

Loop Vm1

Pop si

Pop cx

Ret

VvodMas endp

;______________

Vvod proc

Push ax

Mov ah,0ah

Int 21h

Pop ax

Ret

Vvod endp

;--------------------

;Процедура преобразования строки ASCII в число byte

;Входные параметры: DS:DX+1 - длина строки, DS:DX+2 - строка

; т.е. совпадает с форматом буфера ввода в функции 0A DOS

ConvAb proc

Push si

Push cx

Push dx

Mov si,dx

Mov dl,0; обнулим сумму

Mov mno,1

Lodsb

Jg Ext

Cbw

Dec si

Lodsb

Jl Ext

cmp al,'9'

Jg Ext

Sub al,30h

Mov al,mno

Mul des

Mov mno,al

Cld

Mov al,dl

Pop dx

Pop cx

Pop si

Ret

Mno db 1

ConvAb endp

; выходные параметры:

; AL - число, если произошла ошибка - то, что можно было преобразовать

;-----------------

Imul al

Ret

Sqrr endp

;----------------

SumMas proc

Push si

Push bx

Push cx

Mov bx,0; Обнулим сумму

Mov cx,N

Pop cx

Pop bx

Pop si

Ret

Summas endp

;----------------

Vyvod proc

Push ax

Mov cx,0

New_Delenie:

Div desW

Mov ah,0eh; вывод символа

Int 10h

Loop V

Pop cx

Pop ax

Pop dx

Ret

Vyvod endp

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

Теперь, когда все подпрограммы написаны, приступаем к тестированию программы.

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

Include <имя файла>

Следует только помнить, что директива компилятора include просто включает текст в исходный файл, поэтому необходимо, чтобы все имена переменных и меток были уникальны для обеих файлов.

 

3) Протестировать программу.

Поскольку программа интерактивна, мы можем уже непосредственно запустить её из командной строки файлового менеджера (FAR) или с помощью команды «выполнить» в меню «пуск» Windows. Для проверки работы программы подберите тестовые данные (лучше несколько комплектов) и последовательно запускайте программу, вводя их. В случае, если программа «зависает» или выдает неверный ответ, воспользуйтесь отладчиком Insight для определения ошибочных команд (или данных), выполняя программу по одной команде и наблюдая за результатами команд и логикой её выполнения. При этом вызов подпрограмм может быть выполнен как одна команда, если использовать в отладчике клавишу F8 вместо F7. Найдя ошибку, исправьте текстовый файл с программой, перекомпилируйте и запустите её заново.

Для приведенного примера тестовые данные могут быть например такими – N=5;

A db 1,2,3,3,1

B db 2,4,2,3,0

Результат – 1*1 + 2*2 + 3*3 + 3*3 + 1*1 (= 24)+2*2+4*4+2*2+3*3+0*0=57.

Остальные варианты работ делаются таким же образом.

Практическая работа №5.

Тема: Функции BIOS и DOS для работы с экраном и клавиатурой, использование подпрограмм.

Материалы и оборудование: листы бумаги А4 или тетрадные, авторучка, персональная ЭВМ с установленным отладчиком «Insight», файловым менеджером (Far, NC, Windows Commander и т.п.), компилятором и компоновщиком Ассемблера версии «Турбо- ассемблер 2.0» (tasm.exe, tlink.exe).

 

Цель работы – научиться разработке простейших модульных и интерактивных программ на языке Ассемблера.

 

Выполнение задания

1) Разработать алгоритм решения задачи с использованием модульного программирования.

 

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

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

В данном случае есть два подхода к технологии программирования – нисходящее и восходящее проектирование – при первом подходе сначала составляется общий алгоритм, при этом подпрограммы рассматриваются как «черный ящик», то есть известны данные на входе и на выходе, но неизвестен алгоритм их преобразования. Затем последовательно («сверху-вниз») разрабатываются алгоритмы отдельных модулей. При восходящем проектировании процесс производится в обратном порядке. При структурном программировании (основная технология, применяемая при процедурном программировании, по сути предшественница, но до сих пор актуальная, наиболее популярной в настоящее время технологии объектно-ориентированного программирования).

Состав модулей при модульном программировании отображается на схеме иерархии модулей. Рекомендуется строгая иерархия, то есть чтобы модули не вызывали друг друга на одном уровне иерархии и не «перескакивали» через уровень.

Типичная схема иерархии модулей выглядит следующим образом:

Пример: Вычислить выражение: . Исходными данными служит n и массивы a,b. Использовать подпрограмму вычисления квадрата числа. Исходные данные должны вводиться вручную, а ответ выводиться на экран. Необходимо учитывать возможность переполнения и выдавать в этом случае соответствующее предупреждение.

 

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

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

Алгоритм основной программы:

 

В блок-схеме вызов подпрограммы при этом обозначается прямоугольником с двумя дополнительными линиями по краям. После этого разрабатываются алгоритмы подпрограмм. На блок-схемах алгоритмов подпрограмм вместо слов «начало» и «конец» используются «вход» и «выход». Например, блок-схема алгоритма подпрограммы «ввод массива»:

 

Строгое неравенство здесь обусловлено тем, что индексы в массиве начинаются с 0, соответственно в массиве из 5 элементов последний элемент будет с индексом 4.

И так далее. Не всегда обязательно описывать алгоритм каждого модуля именно блок-схемой, в ряде случаев может быть достаточно словесного описания или описания на языке программирования. Например, возведение числа в квадрат блок-схемой описывать не обязательно, куда понятнее просто команда imul ax. Чем сложнее алгоритм, тем более он нуждается в интуитивно более понятном, по исследованиям психологов, графическом описании.

 

2) Закодировать алгоритм с использованием подпрограмм на языке ассемблера и с использованием ввода-вывода.

 

Процедуры в языке ассемблера следующим способом:

 

<идентификатор> proc

….

<идентификатор> endp

 

Команды вызова – CALL

Команда возврата – RET

 

Например:

CALL VVOD

CALL RASCHET

CALL VYVOD

RET (Возврат из главной программы)

 

VVOD PROC

….

RET

VVOD ENDP

………

 

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

CALL VVOD

 

VVOD:

ret)

Точно также и любые данные могут быть интерпретированы процессором как команда и любая команда (её машинный код) может быть использована процессором как данные. Например:

Db 0B8h,0,0 эквивалентна команде mov ax,0 и наоборот. Такой принцип, вытекающий из архитектуры Фон-Неймана (архитектуры вычислительной системы, при которой для команд и для данных используется общая память), предоставляет программисту на ассемблере уникальные преимущества по сравнению с языками высокого уровня – например, программа может модифицировать себя в процессе выполнения.

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

AA PROC

PUSH AX

PUSH BX

POP BX

POP AX

RET

AA ENDP

 

Форматы команды CALL аналогичны форматам команды JMP.

Команда CALL выполняется следующим образом – в стек записывается адрес возврата (следующей за CALL команды), после чего происходит передача управления (JMP).

Команда RET «достает» из стека сохраненные значения, за счет чего происходит возврат в основную программу и реализуется. Благодаря свойству стека «последний пришел первый ушел» (LIFO) реализуется вложенность подпрограмм и возможность рекурсии (вызова подпрограммой самой себя, рекурсия например может быть использована при вычислении факториала числа). Однако следует помнить, что стек не должен измениться при вызове подпрограммы (то есть количество команд push и pop внутри подпрограммы должно быть одинаковым), иначе команда ret вернет управление совсем не в то место программы, откуда подпрограмма была вызвана.

 

После описания алгоритма необходимо определить соглашение о параметрах на входе и на выходе из процедуры – то есть что и где передается модулю, и что и где он возвращает. Механизмы передачи параметров модулям в языке ассемблера могут быть – через глобальные переменные (то есть общие для всех процедур), через регистры, через стек. В ассемблере переменные не разделяются на локальные и глобальные средствами языка. Передача параметров через стек обычно осуществляется при компиляции программ с языков высокого уровня (Паскаль, Си и т.д.). Наиболее простым решением является передача параметров через регистры.

Состав входных и выходных параметров может быть изображен в виде HIPO-диаграммы (см. практическую работу №2). Или описан в виде таблицы, или представлен непосредственно в программе в виде комментариев (для простых программ). Если подпрограмма изменяет содержимое каких-нибудь других регистров (не связанных с входными и выходными данными), об этом необходимо также упомянуть в составе выходных параметров.

При определении параметров необходимо уже представлять себе используемые в программе команды. Например, адрес памяти должен обязательно передаваться в регистрах, по которым можно адресовать память, если предполагается использовать строковые команды – то надо использовать регистры SI DI, для организации цикла – регистр СХ и т.п.

 

Для нашего примера:

Модуль Входные параметры Выходные параметры
Ввод массива VvodMas DI – адрес массива, который необходимо ввести   По адресу DI – введенный массив; DI изменяется
Суммирование квадратов элементов массива SumMas SI – адрес суммируемого массива   AX – сумма квадратов массива
Вывод числа Vyvod   AX – число Нет (число выводится на экран)
Ввод числа Vvod   DX – адрес буфера для вида числа   По адресу DX – строка, содержащая число (в формате функции 0Ah ДОС)
Преобразование во внутренний формат ConvAb   DX– адрес строки с символьным представлением числа (в формате функции 0Ah ДОС) AL – внутреннее представление числа
Вычисление квадрата Sqrr AL – число AX – квадрат числа

 

Затем, когда разработаны алгоритмы процедур, начинаем кодировать их на языке ассемблера, как делали в предыдущих практических работах. Для того, чтобы закодировать вызов подпрограммы, поступаем следующим образом – сначала записываем нужные параметры (входные для неё) в регистры, затем вызываем подпрограмму командой CALL. В самой подпрограмме перед выходом запишем в нужные регистры результаты её работы (сформируем выходные параметры). Естественно, регистры, в которых подпрограмма возвращает результат, сохранять в стеке не надо, иначе никакого результата возвращено не будет. В частности, основная программа будет выглядеть так:

 

Основная программа:

Model tiny

Code

Org 100h

N equ 5

start:

Mov di,offset A

call VvodMas;ввод массива A

Mov di,offset B



Поделиться:


Последнее изменение этой страницы: 2016-12-17; просмотров: 435; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.147.238.70 (0.234 с.)