Введення
Асемблер дозволяє дуже просто опуститися до «роботи на рівні біт», чого не дозволяють здійснити з такою легкістю багато мов високого рівня. Хоча асемблер і не підтримує такі технології, як ООП, але все-таки в ньому є макросредств, можливість писати модулі, процедури, що так само спрощує розбивку програми на більш прості логічні блоки з метою кращого розуміння програми і можливості вносити зміни тільки в частину коду не змінюючи при цьому весь код програми.
В асемблері зручно те, що ми самі вирішуємо якого типу числа ми зберігаємо в комірках пам'яті (знакові або беззнакові, упаковані).
У даній роботі розробляються модуль для обчислення значення функції, який згодом підключається до програми в якій здійснюється введення вихідних даних з контролем допусімого значення в таблицю, а також відображення цієї таблиці на пристрої виводу, а також модуль для роботи з рядками, який згодом може використовуватися для обробки великих масивів текстової інформації з високою швидкодією.
1. Теоретичні відомості
1.1 Переваги написання програми на асемблері
Так як мова асемблера для комп'ютера «рідний», то і найефективніша програма може бути написана тільки на ньому (за умови, що її пише кваліфікований програміст). Тут є одне маленьке «але»: це дуже трудомісткий, вимагає великої уваги і практичного досвіду процес. Тому реально на асемблері пишуть в основному програми, які повинні забезпечити ефективну роботу з апаратною частиною. Іноді на асемблері пишуться критичні за часом виконання або витрачанню пам'яті ділянки програми. Згодом вони оформляються у вигляді підпрограм і суміщаються з кодом на мові високого рівня.
Мова асемблера буде існувати, поки будуть існувати процесори. Це не минуще і не схильне моді. Володіння мовою асемблера дає відчуття повного володіння комп'ютером, влади над ним.
За допомогою асемблера можна створювати самий компактний і швидкий код. Жоден компілятор мов високого рівня не може давати таких результатів. Багато модулі операційних систем або навіть операційні системи цілком було написано на мові асемблера.
1.2 Типи даних
При програмуванні на мові асемблера використовуються дані наступних типів:
- Безпосередні дані, що представляють собою числові або символьні значення, що є частиною команди.
Безпосередні дані формуються програмістом в процесі написання програми для конкретної команди асемблера.
- Дані простого типу, якi описуються обмеженого набору директив резервування пам'яті, що дозволяють виконати самі елементарні операції з розміщення та ініціалізації числової і символьної інформації. При обробці цих директив асемблер зберігає у своїй таблиці символів інформацію про місцезнаходження даних (значення сегментної складової адреси і зсуву) і тип даних, тобто одиницях пам'яті, що виділяються для розміщення даних відповідно до директиви резервування та ініціалізації даних.
Ці два типи даних є елементарними, або базовими; робота з ними підтримується на рівні системи команд мікропроцесора. Використовуючи дані цих типів, можна формалізувати і запрограмувати практично будь-яке завдання. Але наскільки це буде зручно - ось питання.
- Дані складного типу, які були введені в мову асемблера з метою полегшення розробки програм. Складні типи даних будуються на основі базових типів, які є як би цеглинками для їх побудови. Введення складних типів даних дозволяє дещо згладити відмінності між мовами високого рівня і асемблером. У програміста з'являється можливість поєднання переваг мови асемблера і мов високого рівня (в напрямку абстракції даних), що в кінцевому підсумку підвищує ефективність кінцевої програми.
Обробка інформації, в загальному випадку, процес дуже складний. Це побічно підтверджує популярність мов високого рівня. Одне з безперечних достоїнств мов високого рівня - підтримка розвинених структур даних. При їх використанні програміст звільняється від вирішення конкретних проблем, пов'язаних з поданням числових чи символьних даних, і отримує можливість оперувати інформацією, структура якої більшою мірою відображає особливості предметної області розв'язуваної задачі. У той же самий час, чим вище рівень такої абстракції даних від конкретного їх подання в комп'ютері, тим більше навантаження лягає на компілятор з метою створення дійсно ефективного коду. При програмуванні на мові асемблера використовуються дані наступних типів:
Безпосередні дані, що представляють собою числові або символьні значення, що є частиною команди.
Безпосередні дані формуються програмістом в процесі написання програми для конкретної команди асемблера.
Дані простого типу, якi описуються обмеженого набору директив резервування пам'яті, що дозволяють виконати самі елементарні операції з розміщення та ініціалізації числової і символьної інформації. При обробці цих директив асемблер зберігає у своїй таблиці символів інформацію про місцезнаходження даних (значення сегментної складової адреси і зсуву) і тип даних, тобто одиницях пам'яті, що виділяються для розміщення даних відповідно до директиви резервування та ініціалізації даних.
Ці два типи даних є елементарними, або базовими; робота з ними підтримується на рівні системи команд мікропроцесора. Використовуючи дані цих типів, можна формалізувати і запрограмувати практично будь-яке завдання. Але наскільки це буде зручно - ось питання.
Дані складного типу, які були введені в мову асемблера з метою полегшення розробки програм. Складні типи даних будуються на основі базових типів, які є як би цеглинками для їх побудови. Введення складних типів даних дозволяє дещо згладити відмінності між мовами високого рівня і асемблером. У програміста з'являється можливість поєднання переваг мови асемблера і мов високого рівня (в напрямку абстракції даних), що в кінцевому підсумку підвищує ефективність кінцевої програми.
Обробка інформації, в загальному випадку, процес дуже складний. Це побічно підтверджує популярність мов високого рівня. Одне з безперечних достоїнств мов високого рівня - підтримка розвинених структур даних. При їх використанні програміст звільняється від вирішення конкретних проблем, пов'язаних з поданням числових чи символьних даних, і отримує можливість оперувати інформацією, структура якої більшою мірою відображає особливості предметної області розв'язуваної задачі. У той же саме час, чим вищий рівень такої абстракції даних від конкретного їх подання у комп'ютері, тим більше навантаження лягає на компілятор з метою створення справді ефективного коду.
1.3 Завдання курсового проекту
Варіант номер один. Отже, арифметичне вираз має наступний вигляд:
(A - b) / a + 1, якщо a> b
Y = 25, якщо a = b
(A - 5) / b, якщо a <b
Необхідно:
- Написати модуль на мові Асемблера для обчислення значення виразу (у вигляді процедури або макросу);
- Написати на мові Асемблера програму коректного введення вихідних даних (з контролем допустимого діапазону) в таблицю і виведення отриманого результату у вигляді таблиці;
- Провести тестові перевірки, зробити аналіз результатів;
- Ввести рядок символів. Вивести номер першої цифри в рядку, якщо вона там є;
- Написати модуль на мові Асемблера для обробки рядків (у вигляді процедури або макросу);
- Написати на мові Асемблера програму коректного введення вихідних даних;
- Провести тестові перевірки, зробити аналіз результатів.
2. Арифметика
При запуску програми користувачеві виводяться вказівки, що потрібно робити. Це відбувається за допомогою виклику переривання 21 h c ah = 09 h.
Ось відповідний код:
mov ah, 09h
mov dx, offset str1
int 21h
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
mov di, dx
jmp z1
z2:
cmp si, 0
je z5
cmp al, 13
je enter1
jmp z1
enter1:
mov ah, 2h
mov dl, 13
int 21h
mov ah, 2h
mov dl, 10
int 21h
mov a, di
jmp z6
z5:
mov ah, 2h
mov dl, 13
int 21h
mov ah, 2h
mov dl, 10
int 21h
mov ah, 09h
mov dx, offset str2
int 21h
mov ah, 2h
mov dl, 13
int 21h
mov ah, 2h
mov dl, 10
int 21h
inc i
jmp k3
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
mov di, dx
jmp x1
x2:
cmp si, 0
je z5
cmp al, 13
je enter2
jmp z1
enter2:
mov ah, 2h
mov dl, 13
int 21h
mov ah, 2h
mov dl, 10
int 21h
mov b, di
jmp x6
x5:
mov ah, 2h
mov dl, 13
int 21h
mov ah, 2h
mov dl, 10
int 21h
mov ah, 09h
mov dx, offset str2
int 21h
mov ah, 2h
mov dl, 13
int 21h
mov ah, 2h
mov dl, 10
int 21h
inc i
jmp k3
x6:
Спочатку зчитуємо змінну A, а потім, якщо попереднє читання закінчилося успішно, то зчитуємо змінну B.
Розглянемо їх.
2.2 Запис даних у масиви
Передаємо в стек параметри, тобто змінні а і b, і викликаємо процедуру знаходиться в модулі.
Оригінальний текст модуля представлений в додатку А.
Робимо порівняння змінних виконуємо відповідні арифметично операції, результат заносимо в змінну y 1 і повертаємося в зухвалу програму.
2.3 Запис даних у масиви
Так як для типу змінних ми використовували 2 байта, то індексуємо масив через один, щоб на кожен елемент так само відводилося по два байти.
cmp i, 1
je t1
ja t2
mov ax, a
mov sourcea, ax
mov ax, b
mov sourceb, ax
mov ax, y1
mov dest, ax
jmp t3
t1:
mov ax, a
mov sourcea +2, ax
mov ax, b
mov sourceb +2, ax
mov ax, y1
mov dest +2, ax
jmp t3
t2:
mov ax, a
mov sourcea +4, ax
mov ax, b
mov sourceb +4, ax
mov ax, y1
mov dest +4, ax
t 3:
inc i
Далі посимвольний виводимо на дисплей вміст змінної y 1.
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 перейдемо на нову сходинку
mov dl, 13
int 21h
mov dl, 10
int 21h
В кінці робимо переклад каретки і стежимо за переповнення.
3. Рядки
При запуску програми виводимо запрошення говорить, що максимальна к-ть символів в рядку 255.
3.1 Записуємо введений рядок в масив байт
Робимо це в циклі, поки користувач не натисне Enter або не набере 255 символів.
mov i, 0
mov si, 0
z0:
cmp i, 255
je z1
mov ah, 01h
int 21h;
cmp al, 13;
je z1
mov dest [si], al
inc i
inc si
jmp z0;
z1:
Далі викликаємо процедуру.
3.2 Процедура підрахунку першої цифри
Просто переглядаємо і порівнюємо символи є вони цифрами, якщо так, то запам'ятовуємо номер і повертаємо його в зухвалу програму.
Відповідний код представлений в додатку B.
3.3 Висновок результату
Якщо результат нульовий, то символу нам потрібної в рядку не було. Виводимо повідомлення про це.
cmp number, 0
je z 5
mov al, number;
push -1;
mov cx, 10;
l: mov dx, 0;
div cx;
push dx;
cmp ax, 0;
jne l;
mov ah, 2h
l2: pop dx;
cmp dx, - 1;
je ex
add dl, "0";
int 21h;
jmp l2;
ex:
jmp z6
z5:
mov ah, 09h
mov dx, offset str2
int 21h
z6:
mov ax, 4 c 00 h; Вихід
int 21 h
Інакше виводимо номер символу.
4. Контрольний приклад
Запускаємо додаток для підрахунку функції і вводимо:
16
16
У відповідь отримуємо - 25
0
1
У відповідь отримуємо - -5
200000
У відповідь отримуємо - Wrong input!
Значить програма працює коректно.
Запускаємо додаток для підрахунку номера цифри і вводимо:
Abc 1 c
У відповідь отримуємо - 4
Abcd
У відповідь отримуємо - No digit in this line!
Значить програма працює коректно.
Висновок
У цій роботі були реалізовані дві програми, одна для обчислення функції з введенням і висновком даних в таблицю і на дисплей, і перевірки діапазону вихідних даних, інша - для знаходження номера першого символу в рядку з введенням вихідних даних та перевірки їх коректності.
Так як основні дії були розбиті на модулі - це значно спростило модифікацію і налагодження програми.
Розглянуто основні особливості мови асемблера і низькорівневих мов зокрема.
Перелік літератури
Юров В.І. «Assembler: навчальний курс». - СПб: Питер, 2000.
Пирогов В.Ю. «Асемблер MASM32. Програмування ». - СПб: Питер, 2002.
Д. Батіг. «Мистецтво програмування». Том 1.
Д. Батіг. «Мистецтво програмування». Том 2.
Д. Батіг. «Мистецтво програмування». Том 3.