Модель арифметико-логічного пристрою

Розробка програми на мові програмування Assembler, яка виконує арифметичні операції над числами, моделювання операції віднімання та ділення з фіксованою крапкою з заданою кількістю розрядів, а також перевірка правильності введення заданих чисел.

Рубрика Программирование, компьютеры и кибернетика
Вид курсовая работа
Язык украинский
Дата добавления 21.01.2013
Размер файла 38,6 K

Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже

Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.

Размещено на http://www.allbest.ru/

1. Формати числових даних

програма assembler арифметичний операція

Група арифметичних цілочисельних команд працює з двома типами чисел:

· цілими двійковими числами. Числа можуть мати знаковий розряд або не мати такого, тобто бути числами із знаком або без знаку;

· цілими десятковими числами.

Цілі двійкові числа

Ціле двійкове число з фіксованою точкою - це число, закодоване в двійковій системі числення.

Розмірність цілого двійкового числа може становити 8, 16 або 32 біт. Знак двійкового числа визначається тим, як інтерпретується старший біт в представленні числа. Це 7-й, 15-й чи 31-й біти для чисел відповідної розмірності. Серед арифметичних команд є всього дві команди, які дійсно враховують цей старший розряд як знаковий, - це команди цілочисельного множення і ділення imul і idiv. В інших випадках відповідальність за дії із знаковими числами і, відповідно, зі знаковим розрядом лягає на програміста. Діапазон значень двійкового числа залежить від його розміру і трактування старшого біта або як старшого значущого біта числа, або як біта знака числа (табл. 1).

Таблиця 1. Діапазон значень двійкових чисел

Розмірність поля

Ціле без знаку

Ціле зі знаком

байт

0… 255

-128… +127

слово

0… 65 535

-32768… +32 +767

подвійне слово

0… 4294967295

-2147483648… +2 147 483 647

Десяткові числа

Десяткові числа - спеціальний вид подання числової інформації, в основу якого покладено принцип кодування кожної десяткової цифри числа групою з чотирьох біт. При цьому кожен байт числа містить одну або дві десяткові цифри в так званому двійковій-десятковому коді (BCD - Binary-Coded Decimal). Мікропроцесор зберігає BCD-числа в двох форматах (рис. 1):

· упакованому форматі - в цьому форматі кожен байт містить дві десяткові цифри. Десяткова цифра являє собою двійкове значення в діапазоні від 0 до 9 розміром 4 біти. При цьому код старшої цифри числа займає старші 4 біти. Отже, діапазон представлення десяткового упакованого числа в одному байті становить від 00 до 99;

· неупакованому форматі - в цьому форматі кожен байт містить одну десяткову цифру в чотирьох молодших бітах. Старші чотири біта мають нульове значення. Це так звана зона. Отже, діапазон представлення десяткового неупакованого числа в одному байті становить від 0 до 9.

2. Виконання арифметичних операцій

2.1 Арифметичні операції над двійковими числами

Додавання двійкових чисел без знаку

Мікропроцесор виконує додавання операндів за правилами складання двійкових чисел. Проблем не виникає до тих пір, поки значення результату не перевищує розмірності поля операнда. Наприклад, при додаванні операндів розміром в байт результат не повинен перевищувати число 255. Якщо це відбувається, то результат виявляється невірним. До прикладу, виконаємо додавання: 254 + 5 = 259 в двійковому вигляді. 11111110 + 0000101 = 1 00000011. Результат вийшов за межі восьми біт і правильне його значення вкладається в 9 біт, а в 8-бітовому полі операнда залишилося значення 3, що, звичайно, невірно. Для фіксування ситуації виходу за розрядну сітку результату, призначений прапор переносу cf. Він розташовується в біті 0 регістра прапорів eflags / flags. Саме установкою цього прапора фіксується факт перенесення одиниці зі старшого розряду операнда. В системі команд мікропроцесора є три команди двійкового складання:

· inc операнд - операція інкремента, тобто збільшення значення операнда на 1;

· add операнд_1, операнд_2 - команда додавання з принципом дії: операнд_1 = операнд_1 + операнд_2

· adc операнд_1, операнд_2 - команда складання з урахуванням прапора перенесення cf. Принцип дії команди: операнд_1 = операнд_1 + операнд_2 + значеніе_cf

Додавання двійкових чисел із знаком

Мікропроцесор не підозрює про розходження між числами із знаком і без знака. Замість цього у нього є фіксування виникнення характерних ситуацій, що складаються в процесі обчислень:

· прапор переносу cf, установка якого в 1 говорить про те, що відбувся вихід за межі розрядності операндів;

· команду adc, яка враховує можливість такого виходу (перенесення з молодшого розряду).

Інший засіб - це реєстрація стану старшого (знакового) розряду операнда, яке здійснюється за допомогою прапора переповнення of в регістрі eflags (біт 11).

Приклад 2.1.1.

30566 = 01110111 01100110

+

00687 = 00000010 10101111

=

31253 = 01111010 00010101

Стежимо за переносами з 14-го і 15-го розрядів і правильністю результату: переносів немає, результат правильний.

Приклад 2.1.2.

30566 = 01110111 01100110

+

30566 = 01110111 01100110

=

61132 = 11101110 11001100

Стався перенесення з 14-го розряду; із 15-го розряду переносу немає. Результат неправильний, тому що є переповнення - значення числа вийшло більше, ніж те, яке може мати 16-бітне число зі знаком (+32 767).

Приклад 2.1.3.

-30566 = 10001000 10011010

+

-04875 = 11101100 11110101

=

-35441 = 01110101 10001111

Стався перенесення з 15-го розряду, з 14-го розряду немає переносу. Результат неправильний, тому що замість негативного числа вийшло позитивне (в старшому біті знаходиться 0).

Переповнення (установка прапора of в 1) відбувається при перенесенні:

· з 14-го розряду (для позитивних чисел зі знаком);

· з 15-го розряду (для негативних чисел).

І навпаки, переповнення не відбувається (тобто прапор of скидається в 0), якщо є перенос з обох розрядів або перенесення відсутня в обох розрядах.

Віднімання двійкових чисел без знаку

Якщо зменшуване більше від'ємника, то проблем немає, - різниця позитивна, результат вірний. Якщо зменшуване менше від'ємника, виникає проблема: результат менше 0, а це вже число зі знаком. У цьому випадку результат необхідно звернути. При звичайному відніманні (в стовпчик) роблять позику 1 з старшого розряду. Мікропроцесор надходить аналогічно, тобто займає 1 з розряду, наступного за старшим, в розрядній сітці операнда. Пояснимо на прикладі.

Приклад 2.1.4.

05 = 00000000 00000101

-10 = 00000000 00001010

Для того щоб справити віднімання, зробимо

уявний позику із старшого розряду:

100000000 00000101

-

00000000 00001010

=

11111111 11111011

Тим самим по суті виконується дія

(65 536 + 5) - 10 = 65 531,

Результат -5 в додатковому коді!

Після команди віднімання чисел без знака потрібно аналізувати стан прапора cf. Якщо він встановлений в 1, то це говорить про те, що стався позику із старшого розряду і результат вийшов в додатковому коді.

До команд віднімання відносяться наступні:

· dec операнд - операція декремента, тобто зменшення значення операнда на 1;

· sub операнд_1, операнд_2 - команда віднімання; її принцип дії: операнд_1 = операнд_1 - операнд_2

· sbb операнд_1, операнд_2 - команда віднімання з урахуванням позички (прапора cf): операнд_1 = операнд_1 - операнд_2 - значеніе_cf

Віднімання двійкових чисел із знаком

Мікропроцесору нема чого мати два пристрої - додавання і віднімання. Досить наявності тільки одного - пристрої додавання. Але для вирахування способом додавання чисел із знаком в додатковому коді необхідно представляти обидва операнда - і зменшуване, і від'ємник. Результат теж потрібно розглядати як значення в додатковому коді. Але тут виникають складнощі. Перш за все вони пов'язані з тим, що старший біт операнда сприймається як знаковий. Розглянемо приклад віднімання 45 - (-127).

Приклад 2.1.5.

Віднімання чисел зі знаком 1

45 = 0010 1101

-

-127 = 1000 0001

=

-44 = 1010 1100

Результат вийшов негативний і число потрібно розглядати як доповнення, рівне -44. Правильний результат повинен бути рівний 172. Тут відбулося переповнення мантиси, коли значущий розряд числа змінив знаковий розряд операнда. Відстежити таку ситуацію можна по вмісту прапора переповнення of. Його установка в 1 говорить про те, що результат вийшов за діапазон представлення знакових чисел (тобто змінився старший біт) для операнда даного розміру, і програміст повинен передбачити дії щодо коригування результату.

Інший приклад різниці розглядається в прикладі 7, але виконаємо його способом додавання.

Приклад 2.1.6.

Віднімання чисел зі знаком 2

-45 - 45 = -45 + (-45) = -90.

-45 = 1101 0011

+

-45 = 1101 0011

=

-90 = 1010 0110

Тут все нормально, прапор переповнення of скинутий в 0, а 1 у знаковому розряді говорить про те, що значення результату - число в додатковому коді.

Множення чисел без знаку

Для множення чисел без знака призначена команда

mul сомножітель_1

Існують прапори переносу cf і переповнення of:

· якщо старша частина результату нульова, то після операції прапори cf = 0 і of = 0;

· якщо ж ці прапори ненульові, то це означає, що результат вийшов за межі молодшої частини і складається з двох частин, що і потрібно враховувати при подальшій роботі.

Множення чисел зі знаком

Для множення чисел зі знаком призначена команда

imul операнд_1 [, операнд_2, операнд_3]

Ця команда виконується так само, як і команда mul. Відмінною особливістю команди imul є тільки формування знака.

Якщо результат малий і уміщається в одному регістрі (тобто якщо cf = of = 0), то вміст іншого регістра (старшої частини) є розширенням знаку - всі його біти дорівнюють старшому биту (знакової розряду) молодшої частини результату.

В іншому випадку (якщо cf = of = 1) знаком результату є знаковий біт старшої частини результату, а знаковий біт молодшої частини є значущим бітом двійкового коду результату.

Ділення чисел без знаку

Для ділення чисел без знака призначена команда

div дільник

Дільник може знаходитися в пам'яті або в регістрі і мати розмір 8, 16 або 32 біт. Місцезнаходження діленого фіксоване і так само, як в команді множення, залежить від розміру операндів. Результатом команди ділення є значення частки та залишку.

Після виконання команди ділення вміст прапорів невизначено, але можливе виникнення переривання з номером 0, званого «ділення на нуль».

Ділення чисел зі знаком

Для ділення чисел зі знаком призначена команда

idiv дільник

2.2 Арифметичні операції над двійково-десятковими неупакованими числами

Додавання неупакованих BCDисел

Розглянемо два випадки складання.

Приклад 2.2.1.

Результат додавання не більше 9

6 = 0000 0110

+

3 = 0000 0011

=

9 = 0000 1001

Перенесення з молодшої тетради в старшу немає. Результат правильний.

Приклад 2.2.2.

Результат додавання більше 9

06 = 0000 0110

+

07 = 0000 0111

=

13 = 0000 1101

Тобто ми отримали вже не BCD-число. Результат неправильний. Правильний результат в неупакованому BCD-форматі повинен бути таким: 0000 0001 0000 0011 в двійковому представленні (або 13 в десятковому).

Для корекції операції додавання двох однозначних неупакованих BCD-чисел в системі команд мікропроцесора існує спеціальна команда

aaa (ASCII Adjust for Addition) - корекція результату складання для представлення в символьному вигляді.

Ця команда не має операндів. Вона працює неявно тільки з регістром al і аналізує значення його молодшої тетради:

· якщо це значення менше 9, то прапор cf скидається в 0 і здійснюється перехід до наступної команди;

· якщо це значення більше 9, то виконуються наступні дії:

· до вмісту молодшої тетради al (але не до вмісту всього регістра!) додається 6, тим самим значення десяткового результату коректується в правильну сторону;

· прапор cf встановлюється в 1, тим самим фіксується перенесення в старший розряд, для того щоб його можна було врахувати в наступних діях.

Віднімання неупакованих BCDисел

Ситуація тут цілком аналогічна складанню. Розглянемо ті ж випадки.

Приклад 2.2.3.

Результат віднімання не більше 9

6 = 0000 0110

-

3 = 0000 0011

=

3 = 0000 0011

Як бачимо, позички зі старшої тетради немає. Результат вірний і коригування не вимагає.

Приклад 2.2.4.

Результат віднімання більше 9

6 = 0000 0110

-

7 = 0000 0111

=

-1 = 1111 1111

Віднімання проводиться за правилами двійкової арифметики. Тому результат не є BCD-числом. Правильний результат в неупакованому BCD-форматі повинен бути 9 (0000 1001 в двійковій системі числення). При цьому передбачається позику із старшого розряду, як при звичайній команді віднімання, тобто у випадку з BCD числами фактично повинно бути виконано віднімання 16 - 7. Результат віднімання потрібно коректувати. Для цього існує спеціальна команда:

aas (ASCII Adjust for Substraction) - корекція результату віднімання для представлення в символьному вигляді.

Команда aas не має операндів і працює з регістром al, аналізуючи його молодшу тетраду наступним чином:

· якщо її значення менше 9, то прапор cf скидається в 0 і керування передається наступній команді;

· якщо значення тетради в al більше 9, то команда aas виконує наступні дії:

1. з вмісту молодшої тетради регістру al (зауважте - не з вмісту всього регістра) віднімає 6;

2. обнуляє старшу тетраду регістра al;

3. встановлює прапор cf в 1, тим самим фіксуючи уявну позику із старшого розряду.

Множення неупакованих BCDисел

Для того щоб перемножити два однорозрядних BCD-числа, необхідно:

· помістити один із співмножників в регістр al (як того вимагає команда mul);

· помістити другий операнд в регістр або пам'ять, відвівши байт;

· перемножити співмножники командою mul (результат, як і належить, буде в ax);

· результат, звичайно, вийде в двійковому коді, тому його потрібно скорегувати.

Для корекції результату після множення застосовується спеціальна команда

aam (ASCII Adjust for Multiplication) - корекція результату множення для представлення в символьному вигляді.

Вона не має операндів і працює з регістром ax наступним чином:

· ділить al на 10;

· результат ділення записується так: частку в al, залишок в ah.

Ділення неупакованих BCDисел

Корекція результату повинна виконуватися до основної операції, що виконує безпосередньо поділ одного BCD-числа на інше BCD-число. Попередньо в регістрі ax потрібно отримати дві неупаковані BCD-цифри діленого. Це робить програміст зручним для нього способом. Далі потрібно видати команду aad:

aad (ASCII Adjust for Division) - корекція ділення для представлення в символьному вигляді.

Команда не має операндів і перетворює двозначне неупаковане BCD-число в регістрі ax в двійкове число. Це двійкове число згодом буде грати роль діленого в операції ділення. Крім перетворення, команда aad поміщає отримане двійкове число в регістр al. Ділене буде двійковим числом з діапазону 0… 99. Алгоритм, за яким команда aad здійснює це перетворення, полягає в наступному:

· помножити старшу цифру вихідного BCD-числа в ax (вміст ah) на 10;

· виконати додавання ah + al, результат якого (двійкове число) занести в al;

· обнулити вміст ah.

Далі програмісту потрібно видати звичайну команду ділення div для виконання ділення вмісту ax на одну BCD-цифру, що знаходиться в байтовому регістрі або байтовой комірці пам'яті.

2.3 Арифметичні операції над двійково-десятковими упакованими числами

Упаковані BCD-числа можна тільки додавати і віднімати. Для виконання інших дій над ними їх потрібно додатково перетворювати або в неупакований формат, або в двійкове представлення.

Додавання упакованих BCDисел

Спробуємо скласти два двозначних упакованих BCD-числа.

Приклад 2.3.1.

Додавання упакованих BCD-чисел

67 = 0110 0111

+

75 = 0111 0101

=

142 = 1101 1100 = 220

В двійковому вигляді результат дорівнює 1101 1100 (або 220 в десятковому поданні), що невірно. Це відбувається з тієї причини, що мікропроцесор не підозрює про існування BCD-чисел і складає їх за правилами складання двійкових чисел. Насправді, результат в двійково-десятковому вигляді повинен бути рівний 0001 0100 0010 (або 142 в десятковому поданні).

Як і для неупакованих BCD-чисел, для упакованих BCD-чисел існує потреба якось коригувати результати арифметичних операцій. Мікропроцесор надає для цього команду daa:

daa (Decimal Adjust for Addition) - корекція результату складання для представлення у десятковому вигляді. Команда daa перетворить вміст регістру al у дві упаковані десяткові цифри. Отримана в результаті складання одиниця (якщо результат складання більше 99) запам'ятовується в прапорі cf, тим самим враховується перенесення в старший розряд.

Віднімання упакованих BCDисел

Аналогічно додаванню, мікропроцесор розглядає упаковані BCD-числа як двійкові і, відповідно, виконує віднімання BCD-чисел як двійкових.

Приклад 2.3.2.

Віднімання упакованих BCD-чисел

Виконаємо віднімання 67-75. Так як мікропроцесор

виконує віднімання способом додавання, то і ми підемо

цим:

67 = 0110 0111

+

-75 = 1011 0101

=

-8 = 0001 1100 = 28???

Результат дорівнює 28 в десятковій системі числення, що є абсурдом. У двійково-десятковому коді результат повинен бути рівний 0000 1000 (або 8 в десятковій системі числення).

При програмуванні віднімання упакованих BCD-чисел програміст, як і при відніманні неупакованих BCD-чисел, повинен сам здійснювати контроль за знаком. Це робиться за допомогою прапора cf, який фіксує позику зі старших розрядів.

Саме віднімання BCD-чисел здійснюється простою командою віднімання sub чи sbb. Корекція результату здійснюється командою das:

das (Decimal Adjust for Substraction) - корекція результату віднімання для представлення у десятковому вигляді. Команда das перетворить вміст регістру al у дві упаковані десяткові цифри.

3. Опис роботи програми

Дана програма реалізує модель арифметико-логічного пристрою. Вона виконує арифметичні операції віднімання та ділення над числами.

Після запуску програми відкривається головне вікно, яке має дружній інтерфейс (меню). Меню складається з 4-х пунктів:

1. Віднімання чисел

2. Ділення чисел

3. Виведення інформації про програму

4. Вихід із програми

Якщо натиснути клавішу «1» відбудеться перехід до мітки, де виконуються операція віднімання. Якщо натиснути клавішу «2» відбудеться перехід до мітки, де виконуються операція ділення. Якщо натиснути клавішу «3» відбудеться перехід до мітки, де виводиться інформація про програму. При натисненні клавіші «Escape», відбудеться вихід із програми. Також реалізована можливість повернення із кожного підпункту до головного меню програми. Для цього треба натиснути будь-яку клавішу.

Для введення чисел створенні спеціальні процедури:

· input_integral_part0 - для введення цілої частини числа для віднімання.

· input_fractional_part0 - для введення дробової частини числа для віднімання.

· input_integral_part - для введення цілої частини числа для ділення.

· input_fractional_part - для введення дробової частини числа для ділення.

Процедура bcd2str призначена для переводу BCD-числа в ASCII-рядок.

Для введення символів з клавіатури використовується функція 0Ah переривання 21h. За допомогою цієї функцій, якщо після введення числа ще не натиснута клавіша «Enter», його можна редагувати, використовуючи на клавіатурі стрілки вправо/вліво та клавішу «Backspace».

При введенні числа відбувається перевірка на введений символ. Якщо введено щось інше окрім цифрових значень, то на екрані з'являється повідомлення про помилку.

Під цілу частину числа виділяється 6 байт, під дробову також 6 байт. З урахуванням крапки та знака загальна кількість символів, яка відводиться під число дорівнює 14 байт. Так як формат зберігання числа в пам'яті упакований, в 1 байті зберігається 2 числа. Таким чином для числа виділяється 12 символів до крапки і 12 символів після.

Якщо в цілу або дробову частину числа буде введено більше символів ніж дозволяється, то відбудеться переповнення розрядної сітки і на екрані з'явиться повідомлення про помилку:

«Error! Переповнення розрядної сітки. Повторіть введення».

При виборі одного з пунктів меню, віднімання або ділення, програма спочатку пропонує ввести цілу частину числа А, потім дробову частину числа А, потім цілу частину числа B і в кінці дробову частину числа B. Після цього виконуються відповідні арифметичні операції і результат виводиться на екран.

Пісня виконання арифметичних дій, програма очікує на натиснення будь-якої клавіші для повернення до головного меню.

4. Лістинг програми

model small

code

386

start: mov ax,@data

mov ds, ax

mov es, ax

main_loop: mov ax, 3; очищаем экран

int 10h

mov ah, 9

mov dx, offset string0

int 21h

mov ah, 0

int 16h

cmp al, '1'

je a2

cmp al, '2'

je a1

cmp al, '3'

je a0

cmp ah, 1

jne main_loop

exit: mov ah, 4Ch

int 21h

a0: mov ax, 3; очищаем экран

int 10h

mov ah, 9

mov dx, offset string8

int 21h

mov ah, 0

int 16h

jmp main_loop

; - деление-

a1: mov ax, 3; очищаем экран

int 10h

mov ah, 9

mov dx, offset string1

int 21h

mov string2+30,'A'

mov string3+33,'A'

mov di, offset A

call input_integral_part

call input_fractional_part

inc string2+30; меняю A на B в сообщении 'Vvedit cilu chastynu chysla A'

inc string3+33; меняю A на B в сообщении «Vvedit drobovu chastynu chysla A»

mov di, offset B

call input_integral_part

call input_fractional_part

; при делении используем FPU (блок для работы с вещественными числами)

xor bx, bx

finit; инициализация FPU

fild A; загрузили число А

fild B; загрузили число В

fdivp st(1), st; поделили А на В

fst S; результат деления в переменную

mov di, offset string5

fldz; загрузили в FPU ноль

db 0DFh, 0F1h; fcomip st, st(1); сравниваю число с нулем

jnz a3

mov byte ptr [di], '0'; если целая часть равна нулю

inc edi

jmp b01

a3: fstcw control; устанавливаю режим «округление к нулю»

or control, 0C00h

fldcw control

fld st; дублирую содержимое st(0) в st(1)

frndint; округляю до целого содержимое st(0)

fsub st(1), st; в st(1) остается дробная часть

fldz

db 0DFh, 0F1h; fcomip st, st(1); сравниваю число с нулем

jnz a4

mov al, '0'; если дробная часть равна нулю

stosb

jmp b31

a4: call bcd2str; процедура, которая переведет BCD-число в строку

fldz

b31: db 0DFh, 0F1h; fcomip st, st(1)

jz b01

mov al, ','

stosb

inc bx

fmul y1; умножаю дробную часть на 1.0e17

call bcd2str

b01: mov byte ptr [di], '$'

mov ah, 9

mov dx, offset string6

int 21h

mov ah, 0

int 16h

jmp main_loop

; - вычитание-

a2: mov ax, 3; очищаем экран

int 10h

mov ah, 9

mov dx, offset string7

int 21h

mov x, offset A+11

mov string2+30,'A'

mov string3+33,'A'

call input_integral_part0

inc string2+30; меняю A на B в сообщении 'Vvedit cilu chastynu chysla A'

mov di, offset A+5

call input_fractional_part0

inc string3+33; меняю A на B в сообщении «Vvedit drobovu chastynu chysla A»

mov x, offset B+11

call input_integral_part0

mov di, offset B+5

call input_fractional_part0

mov cx, 12; число состоит из 12 символов

mov di, offset string5; здесь будет результат

mov eax, dword ptr A+4

cmp eax, dword ptr B+4; сравниваем старшие части А и В

jnz @29

mov eax, dword ptr A; если старшие части А и В равны

cmp eax, dword ptr B; сравниваем младшие

@29: jb @25; если В больше чем А отнимем А от В

and bx, 0; начинаем обработку с нулевого байта заодно сделаем CF=0

@27: mov al, byte ptr A[bx]; в AL очередной байт

sbb al, byte ptr B[bx]; вычитание с учетом займа

das; коррекция результата вычитания

mov byte ptr S[bx], al; очередной байт результата

inc bx; переходим к следующему займу

loop @27

jmp @26

@25: mov byte ptr [di], '-'; если В больше чем А поставим перед результатом минус

inc di

and bx, 0; начинаем обработку с нулевого байта заодно сделаем CF=0

@28: mov al, byte ptr B[bx]; в AL очередной байт

sbb al, byte ptr A[bx]; вычитание с учетом займа

das; коррекция результата вычитания

mov byte ptr S[bx], al; очередной байт результата

inc bx; переходим к следующему займу

loop @28

@26: mov bx, offset S+11; распаковываем результат

mov cx, 6

@30: mov al, [bx]

dec bx; уменьшение содержимого регистра на 1

@24: mov ah, 0

ror ax, 4; циклический сдвиг вправо младшая цифра попала в АН, старшая в AL

shr ah, 4; досдвигаем младшую цифру

or ax, '00'; превращаем в АСКИ-символы

stosw; отправляем в строку

@31: loop @30

mov byte ptr [di], ','; выводим дробную часть

inc di

mov cx, 6

@22: mov al, [bx]

dec bx

mov ah, 0

ror ax, 4

shr ah, 4

or ax, '00'

stosw

loop @22

mov ah, 9

mov dx, offset string6; результат на экран

int 21h

mov ah, 0; ждем нажатия на любую клавишу

int 16h

jmp main_loop

; - процедуры-

; - ввод целой части числа для вычитания-

input_integral_part0 proc

@0: mov ah, 9; приглашение на экран

mov dx, offset string2; «введите целую часть числа A»

int 21h

i1: mov ah, 0Ah; функция 0Ah прерывания 21h для ввода строки с клавиатуры

mov dx, offset buffer; сюда пойдет ввод - > buffer db 7,?, 7 dup(?)

; 7 - максимальное число символов, которое можно ввести плюс символ Enter

;? - здесь будет реальное число символов от 0 до 6 не считая Enter

; 7 dup(?) место под максимальное число символов плюс символ Enter

int 21h

mov ch, 0

mov cl, buffer+1; здесь реальное число символов от 0 до 6

mov si, offset buffer+2; здесь начало символьной строки

cmp cl, 6

ja @3er

mov di, 12; считаем, что упакованных символов 12 так как отвели под них 6 байт

sub di, cx; от 12 минусуем реальное число введенных символов

shr di, 1; делим пополам

neg di; умножаем на -1

add di, x; offset A+11 это будет смещение в переменной А, запись идет наоборот

test cx, 1; количество символов было четное или нет?

jz @1

mov ah, 0

inc cx; если не четное добавим один символ и сделаем АН=0

jmp @2

@1: lodsb; получили очередной символ

sub al, '0'

cmp al, 9

ja @3; если не цифра, то сообщим об ошибке

mov ah, al; поместим этот символ из AL в AH

@2: lodsb; получили очередной символ

sub al, '0'

cmp al, 9

ja @3; если не цифра, то сообщим об ошибке

shl al, 4; сдвигаем содержимое AL на 4 бита влево

shr ax, 4; и сдвигаем содержимое AХ на 4 бита вправо - теперь в AL оба упакованных символа

mov [di], al; переводим строку цифр в BCD-число и отправляем в переменную

dec di

dec cx; уменьшаем СХ на 2 так как LOOP тоже отнимет от CX единицу

loop @1

retn; если все нормально выходим из процедуры

@3: mov ah, 9

mov dx, offset string4; при вводе числа допущена ошибка!

int 21h

jmp @0

@3er: mov ah, 9

mov dx, offset string9; сообщение о переполнение разрядной сетки

int 21h

jmp @0

input_integral_part0 endp

; - ввод дробной части числа для вычитания-

input_fractional_part0 proc

@4: mov ah, 9

mov dx, offset string3; введите дробную часть числа A

int 21h

mov ah, 0Ah

mov dx, offset buffer

int 21h

mov ch, 0

mov cl, buffer+1

mov si, offset buffer+2

cmp cl, 6

ja @6er

test cx, 1

jz @5

mov bx, offset buffer+2

add bx, cx

mov byte ptr [bx], '0'

inc cx

@5: lodsb

sub al, '0'

cmp al, 9

ja @6; если не цифра, то сообщим об ошибке

mov ah, al

lodsb

sub al, '0'

cmp al, 9

ja @6; если не цифра, то сообщим об ошибке

shl al, 4

shr ax, 4

mov [di], al; переводим строку цифр в BCD-число

dec di

dec cx

loop @5

retn

@6: mov ah, 9

mov dx, offset string4; при вводе числа допущена ошибка!

int 21h

jmp @4

@6er: mov ah, 9

mov dx, offset string9; сообщение о переполнение разрядной сетки

int 21h

jmp @4

input_fractional_part0 endp

; - ввод целой части для деления-

input_integral_part proc

d0: mov ah, 9

mov dx, offset string2; введите целую часть числа A

int 21h

mov ah, 0Ah

mov dx, offset buffer

int 21h

mov ch, 0

mov cl, buffer+1

mov si, offset buffer+2

cmp cl, 6

ja d2er

xor eax, eax; обнулили регистр ЕАХ

cdq; обнулили регистр EDX

d1: lodsb; получили очередной символ

sub al, '0'

cmp al, 9

ja d2; проверили цифра или нет

imul edx, 10; умножили содержимое EDX на десять

add edx, eax; сложили содержимое EDX и ЕАХ

loop d1; и так столько раз сколько было символов

mov eax, index [6*4]

mul edx; дополнительно умножили EDX на 1000000

mov [di], eax

mov [di+4], edx; поместили содержимое ЕАХ в младшую часть переменной, а EDX в старшую часть

ret

d2: mov ah, 9

mov dx, offset string4; при вводе числа допущена ошибка!

int 21h

jmp d0

d2er: mov ah, 9

mov dx, offset string9; сообщение о переполнение разрядной сетки

int 21h

jmp d0

input_integral_part endp

; - ввод дробной части для деления-

input_fractional_part proc

d4: mov ah, 9

mov dx, offset string3; введите дробную часть числа A

int 21h

mov ah, 0Ah

mov dx, offset buffer

int 21h

mov ch, 0

mov cl, buffer+1

mov si, offset buffer+2

cmp cl, 6

ja d6er

mov ebx, 6

sub bx, cx

xor eax, eax

cdq

d5: lodsb

sub al, '0'

cmp al, 9

ja d6

imul edx, 10

add edx, eax

loop d5

mov eax, index [ebx*4]; дробная часть будет умножена в отличие от целой не на миллион,

; а в зависимости от количества символов на 1,10,100,1000,10000,100000, то есть 6 символов на 1

; 1 символ на 100000

mul edx

add [di], eax; и складываем с находящейся здесь целой частью

adc [di+4], edx

ret

d6: mov ah, 9

mov dx, offset string4; при вводе числа допущена ошибка!

int 21h

jmp d4

d6er: mov ah, 9

mov dx, offset string9; сообщение о переполнение разрядной сетки

int 21h

jmp d4

input_fractional_part endp

; - перевод BCD-числа в ASCII-строку

bcd2str proc

push ecx

fbstp temp

mov ecx, 9; в десятом байте информация о знаке числа

test ebx, ebx

jnz b1

b0: cmp byte ptr [ecx-7+temp], 0

jnz b1

loop b0; пропускаем незначащие (нулевые) разряды слева

b1: mov al, byte ptr [ecx-1+temp]; загружаем первую значащую пару разрядов

cmp al, 9; если в старшей тетраде 0 - пропустить старшую тетраду

ja b2

add al, 30h; младшую тетраду переводим в ASCII

stosb

dec ecx

jz b3

b2: movzx ax, byte ptr [ecx-1+temp]; распаковываем остальные разряды числа

ror ax, 4; выделяем старшую и младшую тетрады

shr ah, 4

add ax, '00'; переводим в ASCII-код

stosw

loop b2

b3: pop ecx

retn

bcd2str endp

data

string0 db 'Model aryfmetyko-logichnogo prystroyu'

db 0Dh, 0Ah, 'Natysnit 1, shob vidnyaty'

db 0Dh, 0Ah, 'Natysnit 2, shob podilyty'

db 0Dh, 0Ah, 'Natysnit 3, shob otrymaty informaciyu pro programu'

db 0Dh, 0Ah, 'Natysnit Esc, shob vyyty z programy$'

string1 db 'Dilennya chysel z fiksovanoyu krapkoyu$'

string7 db 'Vidnimannya chysel z fiksovanoyu krapkoyu$'

string2 db 0Dh, 0Ah, 'Vvedit cilu chastynu chysla A', 0Dh, 0Ah, '$'

string3 db 0Dh, 0Ah, 'Vvedit drobovu chastynu chysla A', 0Dh, 0Ah, '$'

string4 db 0Dh, 0Ah, 'Pry vvedeni chysla dopushena pomylka!', 0Dh, 0Ah, '$'

string9 db 0Dh, 0Ah, 'Error! Perepovnennya rozryadnoi sitky. Povtorit vvedennya', 0Dh, 0Ah, '$'

buffer db 9,?, 9 dup(?)

string6 db 0Dh, 0Ah, 'Rezultat '

string5 db 50 dup ('$')

string8 db 'Programa modelyuvannya operacii vidnimannya ta dilennya'

db 0Dh, 0Ah, 'chysel z fiksovanoyu krapkoyu z zadanoyu kilkistyu rozryadiv.'

db 0Dh, 0Ah, 'Kilkist baytiv v cilyh ta drobovyh chastynah chysla: 6'

db 0Dh, 0Ah, 'Format chysla: upakovanyy'

db 0Dh, 0Ah, 'Vykonav: student grupy KM-105 Galat Yevgeniy$'

A dq?

B dq?

S dq?

index dd 1,10,100,1000,10000,100000,1000000

y1 dq 1.0e17; множитель

save db 108 dup(?)

control dw?; переменная под содержимое регистра CWR

temp dt?; переменная под BCD

x dw?

end start.

Висновки

В результаті виконання курсової роботи була розроблена модель арифметико-логічного пристрою.

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

Відповідно до завдання, в програмі використовується упакований формат числа. BCD-числа зручно використовувати там, де числа повинні бути великими і точними. При використанні двійкових чисел, операції з такими числами досить проблематичні для мови асемблера. До недоліків використання двійкових чисел можна віднести наступні:

· значення величин у форматі слова і подвійного слова мають обмежений діапазон. Якщо програма призначена для роботи в області фінансів, то обмеження суми в рублях величиною 65 536 (для слова) або навіть 4294967296 (для подвійного слова) буде істотно звужувати сферу її застосування;

· наявність помилок округлення;

· представлення великого об'єму результатів в символьному вигляді (ASCII-коді). Ділові програми не просто виконують обчислення; однією з цілей їх використання є оперативна видача інформації користувачеві. Для цього, природно, інформація повинна бути представлена ??в символьному вигляді. Переклад чисел з двійкового коду в ASCII-код вимагає певних обчислювальних витрат. Число з плаваючою крапкою ще важче перевести в символьний вигляд. А от якщо подивитися на шістнадцяткове представлення неупакованої десяткової цифри та на відповідний їй символ у таблиці ASCII, то видно що вони відрізняються на величину 30h. Таким чином, перетворення в символьний вигляд і назад виходить набагато простіше і швидше.

Список літератури

1. Юров В., Хорошенко С. «Assembler: учебный курс»

2. П. Абель «Ассемблер. Язык и программирование для IBM PC»

3. Калашников О.А. «Ассемблер? Это просто! Учимся программировать»

4. Нортон П., Соухе Д. «Язык ассемблера для IBM PC»

5. Эндрю Таненбаум «Архитектура компьютера»

6. Пирогов В.Ю. «Assembler - Учебный курс»

Размещено на Allbest.ru


Подобные документы

  • Поняття арифметико-логічного пристрою. Правила формування прямого, оберненого та додаткового коду двійкових чисел. Побудова електрично-принципової схеми модулю блоку керування, який міг би виконувати не тільки операцію додавання, але й віднімання.

    курсовая работа [1,6 M], добавлен 27.02.2012

  • Розробка машинного алгоритму операції множення в доповняльному коді з пропуском тактів додавання в двійковій системі числення з старших розрядів чисел, представлених у формі з плаваючою комою та операційний автомат. Контроль операції віднімання.

    курсовая работа [45,5 K], добавлен 14.03.2013

  • Проектування процесора для виконання (з використанням доповняльного коду без відновлення розрядів остачі) операції ділення в двійково-десятковій системі числення. Розробка алгоритму виконання операції та операційного автомату. Розробка карти прошивки.

    курсовая работа [263,3 K], добавлен 14.03.2013

  • Теоретичні відомості про язик С++. Розробка програми, що виконує основні арифметичні дії над простими та складними числами на язику С++. Опис алгоритму програми та її код. Інструкція по користуванню. Обгрунтовування вибору та складу технічних засобів.

    курсовая работа [852,8 K], добавлен 30.11.2011

  • Розробка програми на мові програмування Асемблер для обчислення виразу. Розрахунок значень А, В, С у процедурах. Аналіз отриманих результатів за допомогою відлагоджувальника Turbo Debugger при різних заданих значеннях та перевірка їх правильності.

    лабораторная работа [203,4 K], добавлен 09.01.2013

  • Проектування програми керування мікропроцесорним пристроєм світлової індикації на мові С та Assembler. Розробка алгоритму роботи програми, структурної та електричної принципових схем. Здійснення комп’ютерного моделювання для перевірки розроблених програм.

    курсовая работа [710,7 K], добавлен 04.12.2014

  • Розробка програми перевірки логічного мислення людини на мові програмування С++, результатом якої є моделювання координатного переміщення. Визначення структури вхідних та вихідних даних, вибір мови програмування. Розгляд алгоритму рішення задачі.

    курсовая работа [55,8 K], добавлен 28.04.2015

  • Розробка машинного алгоритму та операційного автомату для виконання операції ділення в двійково-десятковій системі числення з відновленням остачі у оберненому коді. Перевірка роботи керуючого автомату з програмованою логікою та натуральною адресацією.

    курсовая работа [178,7 K], добавлен 10.05.2011

  • Розрізняють дві форми подання двійкових чисел у ЕОМ: із фіксованою комою і з "плавучою" комою. Прямий, обернений і додатковий коди двійкових чисел. Алгоритми виконання арифметичних операцій (додавання, множення, ділення) над двійковими числами із знаком.

    лекция [28,1 K], добавлен 13.04.2008

  • Розробка програми калькулятора, що може виконувати найголовніші арифметичні операції над двома числами. Вимоги до апаратного і програмного забезпечення. Опис форм та компонентів програми. Розробка алгоритмів програмного забезпечення. Опис коду програми.

    курсовая работа [57,1 K], добавлен 31.05.2013

Работы в архивах красиво оформлены согласно требованиям ВУЗов и содержат рисунки, диаграммы, формулы и т.д.
PPT, PPTX и PDF-файлы представлены только в архивах.
Рекомендуем скачать работу.