Введение
Ассемблерпозволяет очень просто опуститься до «работы на уровне бит», чего не позволяютосуществить с такой легкостью многие языки высокого уровня. Хотя ассемблер и неподдерживает такие технологии, как ООП, но все же в нем есть макросредства,возможность писать модули, процедуры, что так же упрощает разбивку программы наболее простые логические блоки с целью лучшего понимания программы ивозможности вносить изменения только в часть кода не изменяя при этом весь кодпрограммы.
В ассемблереудобно то, что мы сами решаем какого типа числа мы храним в ячейках памяти (знаковыеили беззнаковые, упакованные).
В даннойработе разрабатываются модуль для вычисления значения функции, которыйвпоследствии подключается к программе в которой осуществляется ввод исходныхданных с контролем допусимого значения в таблицу, а также отображение этойтаблице на устройстве вывода, а также модуль для работы со строками, которыйвпоследствии может использоваться для обработки больших массивов текстовойинформации с высоким быстродействием.
1.Теоретические сведения
1.1 Преимуществанаписания программы на ассемблере
Так как языкассемблера для компьютера «родной», то и самая эффективная программа может бытьнаписана только на нем (при условии, что ее пишет квалифицированныйпрограммист). Здесь есть одно маленькое «но»: это очень трудоемкий, требующийбольшого внимания и практического опыта процесс. Поэтому реально на ассемблерепишут в основном программы, которые должны обеспечить эффективную работу саппаратной частью. Иногда на ассемблере пишутся критичные по времени выполненияили расходованию памяти участки программы. Впоследствии они оформляются в видеподпрограмм и совмещаются с кодом на языке высокого уровня.
Языкассемблера будет существовать, пока будут существовать процессоры. Это непреходяще и не подвержено моде. Владение языком ассемблера дает ощущениеполного обладания компьютером, власти над ним.
С помощьюассемблера можно создавать самый компактный и быстрый код. Ни один компиляторязыков высокого уровня не может давать таких результатов. Многие модулиоперационных систем или даже операционные системы целиком было написано наязыке ассемблера.
1.2 Типыданных
Припрограммировании на языке ассемблера используются данные следующих типов:
– Непосредственныеданные, представляющие собой числовые или символьные значения, являющиесячастью команды.
Непосредственныеданные формируются программистом в процессе написания программы для конкретнойкоманды ассемблера.
– Данныепростого типа, описываемые с помощью ограниченного набора директиврезервирования памяти, позволяющих выполнить самые элементарные операции поразмещению и инициализации числовой и символьной информации. При обработке этихдиректив ассемблер сохраняет в своей таблице символов информацию оместоположении данных (значения сегментной составляющей адреса и смещения) и типеданных, то есть единицах памяти, выделяемых для размещения данных всоответствии с директивой резервирования и инициализации данных.
Эти два типаданных являются элементарными, или базовыми; работа с ними поддерживается науровне системы команд микропроцессора. Используя данные этих типов, можноформализовать и запрограммировать практически любую задачу. Но насколько этобудет удобно – вот вопрос.
– Данныесложного типа, которые были введены в язык ассемблера с целью облегченияразработки программ. Сложные типы данных строятся на основе базовых типов,которые являются как бы кирпичиками для их построения. Введение сложных типовданных позволяет несколько сгладить различия между языками высокого уровня иассемблером. У программиста появляется возможность сочетания преимуществ языкаассемблера и языков высокого уровня (в направлении абстракции данных), что вконечном итоге повышает эффективность конечной программы.
Обработкаинформации, в общем случае, процесс очень сложный. Это косвенно подтверждаетпопулярность языков высокого уровня. Одно из несомненных достоинств языковвысокого уровня – поддержка развитых структур данных. При их использованиипрограммист освобождается от решения конкретных проблем, связанных спредставлением числовых или символьных данных, и получает возможностьоперировать информацией, структура которой в большей степени отражаетособенности предметной области решаемой задачи. В то же самое время, чем вышеуровень такой абстракции данных от конкретного их представления в компьютере, тембольшая нагрузка ложится на компилятор с целью создания действительноэффективного кода. При программировании на языке ассемблера используются данныеследующих типов:
Непосредственныеданные, представляющие собой числовые или символьные значения, являющиесячастью команды.
Непосредственныеданные формируются программистом в процессе написания программы для конкретнойкоманды ассемблера.
Данныепростого типа, описываемые с помощью ограниченного набора директиврезервирования памяти, позволяющих выполнить самые элементарные операции поразмещению и инициализации числовой и символьной информации. При обработке этихдиректив ассемблер сохраняет в своей таблице символов информацию оместоположении данных (значения сегментной составляющей адреса и смещения) и типеданных, то есть единицах памяти, выделяемых для размещения данных всоответствии с директивой резервирования и инициализации данных.
Эти два типаданных являются элементарными, или базовыми; работа с ними поддерживается науровне системы команд микропроцессора. Используя данные этих типов, можноформализовать и запрограммировать практически любую задачу. Но насколько этобудет удобно – вот вопрос.
Данныесложного типа, которые были введены в язык ассемблера с целью облегченияразработки программ. Сложные типы данных строятся на основе базовых типов,которые являются как бы кирпичиками для их построения. Введение сложных типовданных позволяет несколько сгладить различия между языками высокого уровня иассемблером. У программиста появляется возможность сочетания преимуществ языкаассемблера и языков высокого уровня (в направлении абстракции данных), что вконечном итоге повышает эффективность конечной программы.
Обработкаинформации, в общем случае, процесс очень сложный. Это косвенно подтверждаетпопулярность языков высокого уровня. Одно из несомненных достоинств языковвысокого уровня – поддержка развитых структур данных. При их использованиипрограммист освобождается от решения конкретных проблем, связанных спредставлением числовых или символьных данных, и получает возможностьоперировать информацией, структура которой в большей степени отражаетособенности предметной области решаемой задачи. В то же самое время, чем вышеуровень такой абстракции данных от конкретного их представления в компьютере,тем большая нагрузка ложится на компилятор с целью создания действительноэффективного кода.
1.3Задание курсового проекта
Вариант номеродин. Следовательно, арифметическое выражение имеет следующий вид:
(a– b) / a + 1, если a>b
Y= 25, если a=b
(a – 5) / b, еслиa
Необходимо:
– написатьмодуль на языке Ассемблера для вычисления значения выражения (в виде процедурыили макроса);
– написатьна языке Ассемблера программу корректного ввода исходных данных (с контролемдопустимого диапазона) в таблицу и вывода полученного результата в виде таблицы;
– произвеститестовые проверки, сделать анализ результатов;
– ввестистроку символов. Вывести номер первой цифры в строке, если она там есть;
– написатьмодуль на языке Ассемблера для обработки строк (в виде процедуры или макроса);
– написатьна языке Ассемблера программу корректного ввода исходных данных;
– произвеститестовые проверки, сделать анализ результатов.
2. Арифметика
При запускепрограммы пользователю выводятся указания, что нужно делать. Это происходит припомощи вызова прерывания 21h c ah=09h.
Вотсоответствующий код:
mov ah, 09h
movdx, offset str1
int21h
2.1Считывание исходных данных и проверка на диапазон
Далее в циклетри раза считываем исходные данные в переменные a и b. И проверяем, чтобы онибыли в диапазоне от 0 до 65535. В противном случае переходим на следующийпроход цикла и выдаем соответсвующее предупреждение на дисплей.
Это делаетсяв следующем фрагменте кода:
k3:
cmp i, 3
je k2
mov di, 0; Поканичего не введено, считаем что 0
mov si, 0; Номерпозиции в числе
mov bp, 10; Потомбудем умножать на 10
z1: mov ah, 01h
int 21h; Читаемсимвол
cmp al, ‘0’; Еслиэто служебный символ -> r3
jb z2
cmp al, ‘9’; Еслиэто не цифра -> r1
ja z5
mov bl, al; Сохранимсимвол в bl
mov ax, di
mul bp; Умножаемна 10
cmp dx, 0
jne z5; Еслине 0 в DX -> переполнение
mov dl, bl
sub dl, ‘0’; Преобразуемсимвол в цифру
mov dh, 0; DX– цифра
add dx, ax
jc z5; Еслиперенос -> переполнение
inc si
movdi, dx
jmpz1
z2:
cmpsi, 0
jez5
cmpal, 13
jeenter1
jmpz1
enter1:
movah, 2h
movdl, 13
int21h
movah, 2h
movdl, 10
int21h
mova, di
jmpz6
z5:
movah, 2h
movdl, 13
int21h
movah, 2h
movdl, 10
int21h
movah, 09h
movdx, offset str2
int21h
movah, 2h
movdl, 13
int21h
movah, 2h
movdl, 10
int21h
inci
jmpk3
z6:
mov di, 0; Поканичего не введено, считаем что 0
mov si, 0; Номерпозиции в числе
mov bp, 10; Потомбудем умножать на 10
x1: mov ah, 01h
int 21h; Читаемсимвол
cmp al, ‘0’; Еслиэто служебный символ -> r3
jb x2
cmp al, ‘9’; Еслиэто не цифра -> r1
ja x5
mov bl, al; Сохранимсимвол в bl
mov ax, di
mul bp; Умножаемна 10
cmp dx, 0
jne x5; Еслине 0 в DX -> переполнение
mov dl, bl
sub dl, ‘0’; Преобразуемсимвол в цифру
mov dh, 0; DX– цифра
add dx, ax
jc z5; Еслиперенос -> переполнение
inc si
movdi, dx
jmpx1
x2:
cmpsi, 0
jez5
cmpal, 13
jeenter2
jmpz1
enter2:
movah, 2h
movdl, 13
int21h
movah, 2h
movdl, 10
int21h
movb, di
jmpx6
x5:
movah, 2h
movdl, 13
int21h
movah, 2h
movdl, 10
int21h
movah, 09h
movdx, offset str2
int21h
movah, 2h
movdl, 13
int21h
movah, 2h
movdl, 10
int21h
inci
jmpk3
x6:
Вначалесчитываем переменную A, а затем, если предыдущее чтение закончилось успешно, тосчитываем переменную B.
Рассмотримих.
2.2 Записьданных в массивы
Передаем встек параметры, т.е. переменные а и b, и вызываем процедуру находящуюся в модуле.
Исходныйтекст модуля представлен в приложении А.
Делаемсравнение переменных выполняем соответствующие арифметически операции,результат заносим в переменную y1 и возвращаемся в вызывающую программу.
2.3 Записьданных в массивы
Так как длятипа переменных мы использовали 2 байта, то индексируем массив через один,чтобы на каждый элемент так же отводилось по два байта.
cmpi, 1
jet1
jat2
movax, a
movsourcea, ax
movax, b
movsourceb, ax
movax, y1
movdest, ax
jmpt3
t1:
movax, a
movsourcea+2, ax
movax, b
movsourceb+2, ax
movax, y1
movdest+2, ax
jmpt3
t2:
movax, a
movsourcea+4, ax
movax, b
movsourceb+4, ax
movax, y1
movdest+4, ax
t3:
inc i
Далеепосимвольно выводим на дисплей содержимое переменной y1.
2.4 Выводзначения переменной на дисплей
При помощиделения на десять отделяем по одной цифре и выводим ее на дисплей.
mov ax, y1; Выводимоечисло в регисте AX
push -1; Сохраним признак конца числа
mov cx, 10; Делимна 10
l:mov dx, 0; Очистимрегистр dx
div cx; Делим
push dx; Сохранимцифру
cmp ax, 0; Остался0? (оптимальнее or ax, ax)
jne l; нет -> продолжим
mov ah, 2h
l2:pop dx; Восстановимцифру
cmp dx, –1; Дошли до конца ->выход
je ex
add dl, ‘0’; Преобразуем число в цифру
int 21h; Выведемцифру на экран
jmp l2; Ипродолжим
ex:
mov ah, 02h перейдемна новую строчку
movdl, 13
int21h
movdl, 10
int 21h
В концеделаем перевод каретки и следим за переполнениями.
3. Строки
При запускепрограммы выводим приглашение говорящее, что максимальное кол-во символов встроке 255.
3.1Записываем введенную строку в массив байт
Делаем это вцикле, пока пользователь не нажмет Enter или не наберет 255 символов.
movi, 0
movsi, 0
z0:
cmpi, 255
jez1
movah, 01h
int21h;
cmpal, 13;
jez1
movdest[si], al
inci
incsi
jmpz0;
z1:
Далеевызываем процедуру.
3.2 Процедураподсчета первой цифры
Простопросматриваем и сравниваем символы являются ли они цифрами, если да, тозапоминаем номер и возвращаем его в вызывающую программу.
Соответствующийкод представлен в приложении B.
3.3 Выводрезультата
Еслирезультат нулевой, то символа нам нужного в строке не было. Выводим сообщениеоб этом.
cmp number, 0
je z5
mov al, number;
push-1;
movcx, 10;
l:movdx, 0;
divcx;
pushdx;
cmpax, 0;
jnel;
movah, 2h
l2:popdx;
cmpdx, – 1;
jeex
adddl, ‘0’;
int21h;
jmpl2;
ex:
jmpz6
z5:
movah, 09h
movdx, offset str2
int21h
z6:
mov ax, 4c00h; Выход
int 21h
Иначе выводимномер символа.
4. Контрольныйпример
Запускаемприложение для подсчета функции и вводим:
16
16
В ответполучаем – 25
1
В ответполучаем – -5
200000
В ответполучаем – Wrong input!!!
Значитпрограмма работает корректно.
Запускаемприложение для подсчета номера цифры и вводим:
Abc1c
В ответполучаем – 4
Abcd
В ответполучаем – No digit in this line!
Значитпрограмма работает корректно.
Заключение
В даннойкурсовой работе были реализованы две программы, одна для вычисления функции свводом и выводом данных в таблицу и на дисплей, и проверки диапазона исходныхданных, другая – для нахождения номера первого символа в строке с вводомисходных данных и проверки их корректности.
Так какосновные действия были разбиты на модули – это значительно упростиломодификацию и отладку программы.
Рассмотреныосновные особенности языка ассемблера и низкоуровневых языков в частности.
Переченьлитературы
1. Юров В.И.«Assembler: учебный курс». – СПб: Питер, 2000.
2. Пирогов В.Ю.«Ассемблер MASM32. Программирование». – СПб: Питер, 2002.
3. Д. Кнут. «Искусствопрограммирования». Том 1.
4. Д. Кнут. «Искусствопрограммирования». Том 2.
5. Д. Кнут. «Искусствопрограммирования». Том 3.