Методические указания к выполнению лабораторной работы

1) ознакомиться с теоретическим материалом;

2) разобрать реализацию приведенных задач;

3) дописать необходимые команды, создать исполняемые файлы и выполнить программы, реализующие решение задач 1, 2.

4) проверить правильность работы программ на тестах.

Для самопроверки и для контроля преподавателем необходимо выполнить все задачи.

Анализ таблицы кодов ASCII показывает следующее.

В системе кодировки ASCII для любой цифры от 0 до 9 справедливо соотношение

код (цифра) — код (‘0’) = цифра

Так как код символа 0 (‘0’) равен 30 h , то ASCII -код любой цифры от 0 до 9 отличается от соответствующего двоичного представления числа на 30 h .

Поэтому для преобразования ASCII -кода символа (‘0’..’9’) в число, следует из кода символа вычесть 30 h .

При вводе с клавиатуры, например, цифры 5 недостаточно воспользоваться функцией 1 h прерывания 21 h , так как в регистре al в результате будет находиться код символа ’5’, а не число 5.

Для получения числа 5 необходимо еще вычесть 30 h из полученного кода:

mov 21 h ; в al код символа ‘5’

sub al ,30 h ; теперь в al число 5

ЗАДАЧА 1

Пусть в сегменте данных под символическим именем N хранится беззнаковое десятичное число (от 0 до 255). Необходимо записать по адресу KOD цифры (как символы) из десятичной записи числа.

РЕШЕНИЕ

Пусть N = abc , где a , b , c — десятичные цифры числа N .

Для получения правой цифры c надо взять остаток от деления N на 10. Неполное частное от деления — это число ab , ели его разделить на 10, то неполное частное даст цифру а, а остаток — цифру b .

Чтобы получить эти цифры как символы (их затем можно будет вывести на экран), следует к цифре прибавить код ‘0’ (30 h ).

mov ah ,0 ; расширение N в ax до слова (беззнаковое)

div bl ; ah=c, al=ab

mov KOD +2, ah ; записали последнюю цифру

mov ah ,0 ; al = ab , расширение ab до слова (беззнаковое)

div bl ; ah=b, al=a

add ax,’00’ ; ah=b+’0’, al=a+’0’

mov KOD +1, ah ; записали среднюю цифру

mov KOD , al ; записали первую цифру

ЗАДАЧА 2

Ввести десятичное число и записать его в сегмент данных под символическим именем N (размером в один байт).

РЕШЕНИЕ

По очереди вводим цифры и формируем число по схеме Горнера.

Пусть уже введены первые цифры числа, например, 2 и 1, и по ним сформировано число 21. Пусть следующей введена цифра 3. Тогда умножаем предыдущее число на 10 и прибавляем к нему новую цифру: 21*10+3=213. И так для каждой новой цифры.

Замечание. Будем предполагать, что пользователь вводит число в диапазоне 0-255 корректно и ввод завершается нажатием клавиши Enter .

int 21 h ; в al — первый символ

sub al ,30 h ; теперь первая цифра

mov ah ,0 ; расширение до слова

mov cx , ax ; в cx — первая цифра

int 21 h ; в al следующий символ

cmp al ,0 dh ; сравнение с символом Enter

je End ; конец ввода

sub al ,30 h ; в al — следующая цифра

cbw ; расширение до слова

xchg ax , cx ; теперь в ax — предыдущее число, в cx — следующая

Сегодня мы рассмотрим тему «Вывод на экран Assembler» и разберем программу, которая сможет выводить на экран нашей консоли числа. Для этого нам потребуется изучить несколько новых процедур, а также познакомится с подключаемыми библиотеками и системными файлами.

Вспомним о процедурах

Для начала, я напомню вам, что когда мы изучали с вами процедуры Assembler, то я, подводя итоги, написал, что для процедур с параметрами необходим прототип. Да, это так, но есть одно но: если эта процедура не является стандартной, и не описана где нибудь в подключаемой библиотеки.

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

Вывод на экран

А теперь перейдем к коду:

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

Далее будет не очень понятно пока не увидим в действии, но все же попробую объяснить. Первое, что мы делаем, объявляем константу BSIZE со значением 15. Затем в разделе .data , там где объявляются переменные, задаем несколько переменных, которые потребуются как параметры для наших дальнейших процедур.

Стоит отметить переменную buf: запись dup(duplication) говорит о подряд идущих байт, которые выделяются под переменную buf размерностью BSIZE(15). А знак вопроса говорит, что значения байт заранее не определено.

Итак, пока не все понятно, поэтому идем дальше, тут у вас должен сложиться пазл:

Для того, чтобы вывести что нибудь на экран нужно знать дескриптор вывода. Процедура GetStdHandle считывает адрес дескриптора экрана, и по умолчанию записывает его в регистр eax. После, мы записываем это значение из регистра в переменную stdout.

Дальше мы используем процедуру wsprintf. Она нужна для того, чтобы вывести наше сообщение(именно число) в понятном для нас формате, то есть эта процедура преобразования машинного языка в человеческий формат. Для этого используется переменная ifmt.

Ну и за сам вывод отвечает процедура WriteConsoleA. Она принимает 5 параметров, и последним всегда должен идти 0.

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

Запуск программы

А сейчас я покажу вам как все это реализовать на практике, после написания кода.
Я создал файл fifth.asm и поместил его в папку BIN. Затем я открываю командную строку, и перехожу в папку BIN с помощью команды cd C:UsersНикитаBIN (у вас будет другой путь, скорее всего)
Далее компилирую наш файл, прописывая команду amake.bat fifth, если код правильный, то будет как на фото:

Как мы видим, все скомпилировалось без ошибок, но ничего не вывелось на экран. Для того, чтобы наша программа выполнилась, нужно после компиляции запустить файл с расширением .exe(он создается автоматически после правильной компиляции). Прописываем в командной строке fifth.exe, у вас должно получится нечто подобное:

Все прошло успешно! На сегодня на этом закончим c выводом на экран, но в следующих примерах Assembler мы еще будем возвращаться к этой теме, если у вас остались вопросы, то пишите их в комментариях, не забывайте просматривать исходники и предыдущие статьи.

Как выучить английский

В наше время любой человек должен знать английский язык. А тем более программист. Потому что довольно большая часть документации существует только на английском. А профессионал не может ждать, пока кто-то переведёт ему документацию. Он должен уметь быстро получать нужную инфорамцию и использовать её, независимо от того, на каком она языке — на английском или на русском. Ссылки на курсы по английскому.

Что бы ни делала ваша программа, в большинстве случаев она должна выводить какие-то данные на экран. И если в языках высокого уровня это делается “лёгким движением руки”, то в ассемблере для этого приходится как следует помучиться.

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

Итак, выводить строки на экран можно двумя путями:

  1. Посимвольно (то есть в цикле выводить каждый символ строки).
  2. Строку целиком.

Кроме того, в текстовом режиме вывод на экран можно выполнить одним из трёх способов:

  1. С помощью функций DOS.
  2. С помощью функций BIOS.
  3. Путём прямой записи в видеопамять.

Третий способ хорош тем, что он сразу записывает данные в видеопамять, что позволяет выполнять вывод более быстро. Однако в наше время он применим, разве что, в учебных целях. Потому что современные операционные системы не позволяют напрямую обращаться к “железу”.

Поэтому, если ваша программа является чуть более, чем учебной, то придётся применять один из первых двух способов. Ну а если вам интересно, как выполнить вывод непосредственно в видеопамять, то посмотреть примеры вы можете здесь или здесь.

Функции вывода DOS

Итак, начнём с функций вывода DOS. Эти функции являются функциями операционной системы DOS, но поддерживаются и операционными системами Windows.

Как я уже говорил, можно напечатать на экране строку в цикле, отдельно выводя каждый символ. Для этих целей можно использовать функции 02h, 06h или недокуметированное прерывание 29h.

Если требуется вывести на экран строку целиком, то можно применить функции 09h и 40h.

Для использования функций DOS надо сначала подготовить необходимые данные, записать номер функции в регистр AH, а затем вызвать прерывание 21h.

Все функции рассматривать здесь не будем. Для примера используем одну из самых простых функций DOS — функцию 09h, которая выводит в стандартное устройство вывода (в нашем случае — на экран) строку, адрес которой находится в DS:DX. Строка должна заканчиваться символом $, иначе функция не поймёт, где конец строки, и программа будет выводить много-много символов из памяти, начиная с указанного адреса. Примерно так, как показано на рисунке:

При правильном использовании на экран будет выведено примерно следующее:

Функции вывода BIOS

Функции BIOS также могут выводить как отдельные символы (функции 09h, 0Ah, 0Eh), так и строки целиком (функция 13h).

Кроме того с помощью функций BIOS можно установить видеорежим, установить или считать положение курсора, а также считать символ и его атрибуты.

Хотя функции DOS тоже могут считывать символы, но всё-таки возможности BIOS более широки.

Для работы с функциями BIOS также сначала надо подготовить данные, записать номер функции в регистр AH, а затем вызвать прерывание 10h.

Для примера рассмотрим функцию 13h. Перед вызовом функции надо:

  • Записать номер функции в регистр АН.
  • Записать режим вывода в регистр AL:
  • бит 0: переместить курсор в конец строки после вывода.
  • бит 1: строка содержит не только символы, но и атрибуты. Так что каждый символ описывается двумя байтами — ASCII-код и атрибут. Это можно использовать, если в строке символы должны иметь, например, разный цвет. Если атрибуты одинаковы для всей строки, то этот бит лучше сбросить (обнулить).
  • биты 2-7: не используются.
  • Записать длину строки в регистр СХ (только число символов, байты атрибутов не учитываются).
  • Если строка содержит только символы, то записать в регистр BL атрибут. Этот атрибут будет применяться для всей строки.
  • Записать координаты экрана, начиная с которых будет выводиться строка, в регистры DL (столбец — координата Х) и DH (строка — координата Y).
  • Записать адрес начала строки в ES:BP.
  • Рассказывать об остальных функциях, а также об установке атрибутов и прочих вещах сегодня не буду. Если кому интересно, то всё это можно найти в справочных материалах.