Результат работы программы




Содержание

Введение

. Теория

. Блок-схема

. Код программы

Результат работы программы

Заключение

Список используемых источников

 


Введение

 

Не смотря на то, что язык программирования Ассемблера, в чистом виде, относительно редко используется на практике, его изучение является необходимой частью подготовки профессиональных программистов, поскольку позволяет шире понять принципы работы ЭВМ, операционных систем и трансляторов с языков высокого уровня.

 


Теория

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

Программируя на ассемблере, прежде всего надо помнить, что Вы даёте команды процессору, а для процессора любое устройство является внешним. Понимание этого поможет понять логику программ. Переход с языка высокого уровня (ЯВУ) на ассемблер обычно происходит со скрипом. Первое время достаточно болезнено воспринимается отсутствие оператора print/write/printf/echo, но потом чувствуешь себя хозяином положения и ощущаешь полную власть над компьютером. Нет неграмотных, медленнодействующих операторов, нет таинственных модулей. Всё открыто. В качестве примера совершенно неграмотного модуля можно вспомнить egavga.bgi в Паскале, который вызывает прерывание для рисования каждой отдельной точки.

Конечно при программировании на ассемблере ощущаются и свои недостатки. Главный из них - трудная программируемость некоторых устройств.

Основные команды ассемблера:эквивалент оператора присваивания в ЯВУ. Принимает строго 2 операнда: куда и что. Например, если мы напишем mov ax,bx - в регистр ax запишется значение, хранящееся в регистре bx (ax=bx).арифметическое сложение. Принимает 2 операнда: к чему и сколько. Пример: add ax,bx выполняет ax = ax + bx.вычитание. синтаксис аналогичен add.сдвиг влево на заданное количество бит. При этом старшие биты теряются (кроме последнего, он записывается в флаг CF регистра флагов).сдвиг вправо аналогично shl.безусловный переход. Операнд - адрес перехода (вместо адреса можно использовать метку, которая при трансляции заменится на соответствующий адрес)./or/xor/not логические операции: конъюнкция, дизъюнкция, исключающее или (сложение по модулю 2), инверсия.инкремент (увеличение операнда на 1).декремент (уменьшение оперенда на 1).перейти к подпрограмме. Операнд - адрес начала подпрограммы.вернуться из подпрограммы.вызвать прерывание. Операнд - номер прерывания.поместить операнд в стек.извлечь операнд из стека.принять байт от устройства. in al,60h принимает байт в регистр al от регистра данных контроллера клавиатуры.послать байт устройству. mov al, 0EDh out 60h,al mov al,111b out 60h,al - эта последовательность из четырёх коменд зажигает все светодиоды клавиатуры.no operation - команда ничего не делает (и, как ни странно, имеет применение).команда делает переход на указанную позицию и уменьшает значение CX. Если CX=0, то происходит выход из цикла.группа команд, осуществляющих переход на указанную позицию, если выполнено условие. Например, команда jz передаёт управление в случае, если флаг zf (zero flag) установлен в "1". Этот флаг устанавливается в "1", если после выполнения какой-либо операции операнд становится равным 0 (независимо от его значения до выполнения операции).сравнить. Команда не выполняет каких-либо "видимых" действий. Она просто устанавливает флаги в соответствии с результатом сравнения. После этой команды обычно следует оператор группы jcc. Рассмотрим основные (o1, o2 - операнды команды cmp):zf=1o1=o2cf=1, jnae o1 < o2, без знака, jnbe o1 > 02, без знака, jae o1 >= o2, без знака, jna o1 <= o2, боз знака, jnge o1 < o2, со знаком, jnle o1 > o2, со знаком, jge o1 <= o2, со знаком, jng o1 >= o2, со знакомзагрузить байт по адресу ds:si в регистр al.загрузить слово (2 байла) по адресу ds:si в регистр ax.загрузить двойное слово (4 байта) по адресу ds:si в регистр eax.послать байт по адресу es:di из регистра al.послать слово (2 байла) по адресу es:di из регистра ax.послать двойное слово (4 байта) по адресу es:di из регистра eax.

Команды обмена данными: MOV, XCHG.приемник,источник

Копирует байт(byte)/слово(word)/двойное слово(dword) из операнда источник в операнд приемник. Позволяет копировать данные из одного регистра общего назначения (РОН) в другой, из РОН в память, из памяти в РОН. Командой MOV нельзя напрямую переслать данные из одной области памяти в другую - для этого придется использовать в качестве посредника один из РОН. Копирование данных в таком случае осуществляется за две команды: сначала из исходной области памяти в РОН, а затем - из РОН в целевую область памяти. При помощи команды MOV также можно помещать в регистр или память непосредственное значение, копировать содержимое сегментного регистра в РОН или память, содержимое РОН или памяти в сегментный регистр, содержимое регистра управления или отладки в РОН, содержимое РОН в регистр управления или регистр отладки. Команда MOV может быть обработана компилятором только если размеры источника и приемника совпадают. Ниже следуют примеры возможных вариантов использования команды MOV:bx,ax; копировать содержимое РОН в РОН[char],al; РОН в памятьbl,[char]; память в РОНdl,32; значение в РОН[char],32; значение в памятьax,ds; сегментный регистр в РОН[bx],ds;сегментный регистр в памятьds,ax; РОН в сегментный регистрds,[bx]; память в сегментный регистрeax,cr0; регистр управления в РОНcr3,ebx; РОН в регистр управленияоперанд1,операнд2

Используется для двунаправленной пересылки данных между операндами. Размер обоих операндов может быть байтом, словом или двойным словом, но оба операнда должны быть одинакового размера. Команда XCHG помещает содержимое первого операнда во второй, а второго - в первый. Один из операндов всегда должен быть РОН, а другой может быть областью памяти или также РОН.ax,bx; обменять содержимое РОН и РОНal,[char]; обменять содержимое РОН и памяти

Обмен данными через стек: PUSH, POP.

Стек - область памяти, специально выделяемая каждой программе для временного хранения промежуточных данных. Обычно адреса в памяти растут от ноля к максимальному адресу. В стеке все наоборот: он растет от дна (максимальный адрес сегмента стека) к нолю. Для того, чтобы поместить данные в стек, применяется команда PUSH, ее синтаксис следующий:источник

Эта команда уменьшает указатель на текущий кадр стека (регистр ESP) и копирует содержимое операнда-источника по адресу вершины стека, содержащемуся в ESP. В роли операнда может выступать РОН, память, сегментный регистр, значение размером в слово или двойное слово. Если в качестве операнда указано непосредственное значение, то в 16-битном режиме оно по умолчанию воспринимается компилятором как слово, а в 32-битном - как двойное слово. Мнемоники PUSHW и PUSHD указывают компилятору, что значение необходимо сохранить как слово или как двойное слово соответственно независимо от режима, в котором работает компилятор. Если за командой PUSH следуют несколько операндов, разделенных пробелами, то они будут обработаны компилятором как последовательность из нескольких команд PUSH с этими операндами по отдельности. PUSHA сохраняет в стеке содержимое всех восьми регистров общего назначения. Примеры использования команды PUSH:ax; сохранить РОНes; сохранить сегментный регистр[bx]; сохранить память1000h; сохранить значениеebx,esi,edi; сохранить по очереди три регистра; сохранить все 8 РОНприемник

Команда POP копирует слово или двойное слово, содержащееся на вершине стека, в указанный операнд-приемник, затем увеличивает ESP так, чтобы он указывал на новую вершину стека. Операндом может быть РОН, память, сегментный регистр. Эта команда предназначена для извлечения из стека данных, сохраненных командой PUSH. Следует помнить, что извлекаются данные в обратном порядке, так что, если вы сохранили в стеке EAX, EBX и потом ECX, то извлекать надо сперва ECX, затем EBX и EAX. Команда POP является полной противоположностью команды PUSH, поэтому мнемоники POPW, POPD и POPA работают по аналогии с описанными выше мнемониками PUSH, но выполняют обратные действия.

Примеры:bx; восстановить РОНds; восстановить сегментный регистр[si]; восстановить памятьedi,esi,ebx; восстановить по очереди три регистра; восстановить все 8 РОН

Арифметические команды.операнд

Команда увеличивает значение операнда на единицу. Операнд может быть РОН или памятью. Размер операнда - байт, слово или двойное слово. Примеры:ax; увеличить значение в регистреbyte[bx]; увеличить значение в памятиприемник, источник

Складывает оба операнда и помещает результат в приемник. Если результат превысил размер приемника, устанавливает флаг переноса (CF). Размером операндов может быть байт, слово или двойное слово. Приемник может быть РОН или памятью. Источник может быть РОН или значением. Источник может также быть памятью при условии, что приемник является регистром. Примеры:ax,bx; прибавить к регистру регистрax,[si]; прибавить к регистру память[di],al; прибавить к памяти регистрal,48; прибавить к регистру значение[char],48; прибавить к памяти значениеприемник, источник

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

Команда уменьшает значение операнда на единицу. Правила для операнда те же, что и у INC.приемник, источник

Вычитает источник из приемника, помещает результат в приемник. Если источник был больше приемника, то устанавливается флаг переноса CF. Если источник был равен приемнику (результат 0), то устанавливается флаг ноля ZF. Правила для операндов те же, что и у ADD.приемник, источник

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

Команда осуществляет сравнение приемника с источником способом вычитания источника из приемника, но, в отличие от SUB, результат никуда не сохраняет. По установленным командой флагам можно отследить результат такого сравнения и выполнить условный переход (JZ, JO, JC и т.п.).приемник

Изменяет знак операнда на противоположный, вычитая операнд из нуля. На практике команда применяется не только для смены знака, но и для вычитания из константы. Допустим, нам надо вычесть содержимое AX из 300. Очень хочется написать: sub 300,ax, но команда SUB не допускает возможности вычитания из непосредственного значения, потому что приемник должен являться РОН или памятью. Значит, мы могли бы предварительно поместить значение 300 в какой-то РОН, а затем вычесть из него AX, однако более простым вариантом с точки зрения процессора будет такой:axax,300

Мы прибавили 300 к отрицательному значению ax, что по законам математики дает такой же результат, что и вычитание ax из 300.приемник, источник

Еще одна редкая, но иногда очень полезная команда. Она похожа на ADD, только перед тем, как поместить сумму операндов в приемник, производит обмен значениями между операндами (как команда XCHG). Эта команда одним махом выполняет сразу 2 действия, а значит, может помочь сэкономить процессорное время.

Все вышеперечисленные арифметические операции изменяют флаги SF, ZF, PF, OF в соответствии с результатом. Команды MUL(умножение) и DIV(деление) были достаточно подробно описаны в предыдущей статье, поэтому не будем повторяться, и идем дальше.

Преобразование типов

Размеры операндов арифметических команд должны быть одинаковыми. Поэтому, если необходимо произвести арифметическое действие над операндами, имеющими разные размеры, следует сначала преобразовать один из них так, чтобы оба операнда имели одинаковый размер. Для этого в системе команд процессора предусмотрены команды преобразования типов. Они служат для преобразования байтов в слова, слов - в двойные слова, двойных слов - в учетверенные (qword). Эти преобразования могут выполняться способом знакового расширения - увеличение размера операнда с учетом знака (заполнение старших разрядов увеличенного операнда значением старшего бита исходного операнда) или нулевого расширения (заполнение старших разрядов увеличенного операнда нолями).

Команды преобразования со знаковым расширением без операндов:преобразовывает байт, содержащийся в регистре AL, в слово, помещаемое в регистр AX.преобразовывает слово, содержащееся в регистре AX, в двойное слово, помещаемое в регистры DX:AX. Старшая часть значения разместится в DX, а младшая - в AX.преобразовывает слово, содержащееся в регистре AX, в двойное слово, помещаемое в регистр EAX.преобразовывает двойное слово, содержащееся в EAX, в учетверенное слово, помещаемое в регистры EDX:EAX.

Еще раз напомню, что все перечисленные преобразования по сути своей - лишь распространение значения старшего (знакового) бита исходного операнда на все биты добавляемой части. Эти команды работают с конкретными регистрами и поэтому не имеют операндов.приемник, источник

Преобразовывает с учетом знакового расширения байт в слово или двойное слово; слово - в двойное слово. Операнд-источник может быть памятью или РОН, приемник всегда должен быть РОН.приемник, источник

Работает так же, как и MOVSX, только производит расширение без учета знака, то есть заполняет добавляемую часть нулями, а не знаковым старшим битом источника.

Десятичная арифметика

Десятичные числа могут быть представлены в так называемом двоично-десятичном коде (Binary Coded Decimal - BCD). Этот способ предполагает хранение каждой десятичной цифры в четырех битах. Различают два формата хранения BCD-чисел:

упакованный, когда каждый байт (8 бит) может содержать две десятичные цифры (по 4 бита каждая). В таком случае каждый байт содержит десятичное число в диапазоне от 00 до 99.

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

Десятичная арифметика осуществляется методом комбинирования вышеописанных команд двоичной арифметики с командами, специально предназначенными для десятичных операций. Команды десятичной арифметики используются для приведения результата предыдущих двоичных вычислений к упакованному/неупакованному формату BCD-числа или, наоборот, для подготовки введенных данных к двоичным арифметическим операциям.корректирует результат сложения двух упакованных BCD-чисел в регистре AL. Эта команда должна следовать за командой сложения (ADD или ADC), если в сложении участвовали два упакованных BCD, и результат находится в AL. Если откорректированный результат превысит 99, то будет установлен флаг CF, а в AL останутся лишь две младшие цифры. Пример:al,49hbl,52hal,bl

В данном примере наглядно показано, что упакованные BCD можно записывать просто как шестнадцатеричные числа (буковка h в конце числа означает HEX), только без использования символов ABCDEF. Когда будет произведено сложение 49h и 52h, результат будет неверным. Точнее, он будет верным, но лишь применительно к шестнадцатеричным числам, потому что процессор, складывая эти числа, считает их не упакованными десятичными, а стандартными двоичными или шестнадцатеричными, если хотите. Однако команда DAA все расставляет по своим местам, и в результате в AL получается 01 (две младшие цифры от 101), а установленный флаг CF позволяет определить, что единичка для следующего третьего разряда "в уме".работает аналогично DAA, только используется для корректировки результата вычитания. У команды также отсутствует операнд, потому что действие производится над регистром AL. Флаг CF (если установлен) указывает на то, что вычитаемое оказалось больше уменьшаемого, и необходимо это дело обработать, например, уменьшением третьего разряда на единицу.предназначена для корректировки результата сложения НЕ упакованных BCD-чисел размером в байт, то есть одноразрядных. Операнды отсутствуют, действие производится над регистром AL. Если результат превышает 9, то в AL помещается лишь младший разряд, а AH увеличивается на единицу, и устанавливается флаг CF.аналогична AAA за исключением того, что применяется для корректировки вычитания неупакованных одноразрядных BCD-чисел. При необходимости заема устанавливается флаг CF, а содержимое AH уменьшается на единицу.корректирует результат умножения двух неупакованных BCD, находящийся в AL. Данная команда просто делит содержимое AL на 10 и помещает частное в AH, а остаток - в AL. Таким образом, в AX помещается двухразрядное неупакованное BCD. Стандартная версия команды не имеет операндов, однако существует расширенная версия AAM, в которой в роли операнда выступает непосредственное значение - база, на которую будет производиться деление. Так что, выполнив, к примеру, команду AAM 5, вы поделите нацело содержимое AL, получив частное в AH, а остаток - в AL. Очень удобный способ для деления нацело небольших (до 8 бит) чисел.подготавливает к делению неупакованное BCD-число, находящееся в AX. Команда просто добавляет к AL содержимое AH, умноженное на 10, потом AH обнуляется. Несмотря на свое основное назначение, команда отлично справляется не только с подготовкой к делению, но и с простым преобразованием неупакованного двузначного BCD в двоичный эквивалент. Также команда может оказать неоценимую помощь в преобразовании символьного кода цифр сразу в двоичный код. Например, в таблице ASCII цифра "1" имеет код 31h, цифра "2" - 32h и т.д. Значит, для того, чтобы из символьного кода получить неупакованное BCD, нам достаточно обнулить старший шестнадцатеричный разряд (старшие 4 бита) ASCII-кода. Поместим число 15 в символьном виде в AX и переведем его в двоичное значение:AX,3135hAX,0F0Fh; обнуляем левые половинки байтов

После выполнения этих команд в AX у нас будет 0Fh, то есть число 15 в нормальном двоичном (шестнадцатеричном) виде, привычном для процессора. В расширенном варианте команды AAD есть возможность указать в качестве операнда непосредственное значение, на которое будет умножаться AH, прежде чем прибавиться к AL. Это дает еще один вариант использования команды: быстрое умножение небольших чисел.

 


Блок схема

 


Код программы

; Разработчик: Киселёв Роман Сергеевич

.stack 100h

.datadb 255,255 dup (?); буфер для строки, хранящей имя файла

; строки сообщений, которые будут выводиться на экранdb 'Enter File Name: $'db 0ah,0dh,'Open File Error ',0ah,0dh,'$'db 0ah,0dh,'File Is Not BMP',0ah,0dh,'$'db 0ah,0dh,'File Is Not Monochrome BMP',0ah,0dh,'$'db 0ah,0dh,'Read File Error',0ah,0dh,'$'db 0ah,0dh,'Image Size must be less than 320x200',0ah,0dh,'$'

; структура BITMAPFILEHEADERdw?; информация о типе файлаdd?; размер самого файла в байтахdw 0; нули (зарезервировано)dw 0; тоже нулиdd?; смещение относительно начала файла и битовый массив растраequ $-bfType; константа, хранящая размер заголовка

; Структура BITMAPINFOHEADERdd?; размер структуры BITMAPINFOHEADER в байтахdd?; ширина изображения (в пикселях)dd?; высота изображения в пикселяхdw?; количество плоскостейdw?; кол-во бит на пиксельdd?; тип сжатияdd?; размер изображения в байтахdd?; горизонтальное разрешениеdd?; вертикльное разрешениеdd?; текущее число цветов графического движкаdd?; кол-во важных цветовequ $-biSize; константа для хранения размера структуры BITMAPINFOHEADER

; структуры, необходимые для считывания палитры

; RGBQUAD для 1 цветаB db?G db?R db?Q db?

; RGBQUAD для 2 цветаB db?G db?R db?Q db?equ $-c1B; константа для хранения размеров палитрыequ 4000; размер блока при чтении растраdb BlockSize dup (?); массив битов растраdw?; используется при рисовании - текущее зн-ие колонкиdw?; текущее значение строкиdb 0; число битов, которые не входят в изображение, но присутствуют в каждой строке для выравнивания ее по параграфуdb?; переменная для хранения предыдущего видеорежимаdw?; Дескриптор открытого файла_Option db 0; Байт, хранящий информацию о том, включена ли опция/I

;Если выключена, то I_Option=0, иначе - любое значение, отличное от нуля (если конкретно - 1)

.code

; Макрос для вывода строки на экранmacro str_addrah,09dx,str_addr21h

;Макрос для вывода сообщения об ошибке и перехода в начало программыmacro str_addrstr_addrBegin

; Макрос для чтения данных из файлаmacro buf_addr,StrucSizeah,3fh; ф-ия для чтения из файлаbx,Descriptor; дескриптор файлаdx,buf_addr; адрес на начала буфераcx,StrucSize; размер структуры21h:ax, @data; инициализация сегмента данныхds,axCmdAnalyze; Вызов анализатора командной строки. в dh будет записано после вызова кол-во символов в имени файла.ax,0A000h; инициализация es. es будет указывать на сегмент видеобуфераes,axdh,dh; если строка параметров (имя файла) _OpenFile; _ не пуста, то сразу переходим к открытия файла

; если она пуста то _Begin; переходим на ввод имени файла с клавиатуры

; сообщения об ошибках:; если файл не найденEMsg1Error:; если ошибка чтения из файлаCloseFileEMsg4:; если файл не является файлом BMPCloseFileEMsg2:; вывод сообщения об ошибке в случае, если BMP не является монохромнымCloseFileEMsg3:; преждевременное завершение программыax,4C00h21h:; на эту метку будем возвращаться при ошибках. Фактически, при неверном формате указанного файла, будем возвращаться сюда и снова запрашивать имя файла

; вывод на экран приглашения для ввода имени файлаmsg

; ввод имени файла с клавиатурыah,0ah; 0ah - ф-ия для буферизированного ввода строки с клавиатурыdx,offset fname21h

; формирование строки имени файла для последующего открытия функцией сервиса DOSbx,dx; по адресу в bx лежит размер буфера fname для вводаbx; по адресу в bx - количество байт в строкеal,[bx]; в al - кол-во записанных байт в fnamebl,al; теперь bx указвает на последний записанный байт в строкеbl; bx указывает на след. после последнего байт[bx],0; и помещаем туда ноль-байтal,al; если ввели пустую строку _ExitNow; _ то выходим из программы:

; Откроем файлdx,fnameah,3dh; ф-ия для открытия файлаal,al; режим - чтениеdxdx; теперь dx указывает на начало строки fname21h; открыли файлFileNotFound; если ошибка - выдаем сообщение - снова вводим имя файлаDescriptor,ax

; Читаем BITMAPFILEHEADERbfType,HeaderSizeRead1Error

; Проверка сигнатуры формата BMPax,word ptr bfType; в ax помещаем первые 2 байта структуры заголовка. Они должны быть BMax,'MB'; поскольку слова в памяти хранятся в обратном порядке - то сравниваем именно с MBFileNotBMP; Если первые 2 байта не BM, то сообщаем о том, что файл не BMP и снова идем на ввод имени файла

; Чтение структуры BITMAPINFOHEADER из файлаbiSize,InfoHeaderSize

; Проверка: является ли BMP монохромным?dx,[biBitCount]; в dx - количество бит на 1 пиксель в картинкеdx,1; сравниваем кол-во бит на пиксель с единицей. Единица - говорит о том, что битмап монохромныйFileNotMonoChrome; если изображение не монохромное, то говорим об этом и снова запрашиваем имя файла

; Выполним обработку опции командной строки /Idl,I_Optiondl,dl; если опция включена _SkipSizeCheck; _ то пропускаем проверку размеров изображенияdx, word ptr [biWidth]; в dx - ширина изображенияdx,320; если ширина изображения _IncorrectSize; больше чем 320, то сообщаем о неверном размереdx, word ptr [biHeight]; в dx - высота изображенияdx,200; если больше чем 200, то _IncorrectSize; _ то сообщаем о неверном размере:

; считываем палитру

; для монохромных изображений - 2 цвета, 2 структуры RGBQuad. Сc1B,PalleteSizeReadFileError

; перемешаемся в файле на bfOffBits, т. е. на начала массива растраah,42h; ф-ия для перемещения по файлуbx,Descriptor; восстанавливаем дескриптор файла из стекаal,al; устанавливаем режим смещения - относительно начала файлаdx,word ptr bfOffBits; смещение указывается как (CX * 65536) + DX. Вобщем-то DX всегда будет равен 3E для монохромных изображение, а CX=0cx,word ptr bfOffBits+121h; перемещаемся

; установка графического режимаSetDisplay

; инициализация начальных параметров рисованияcx,word ptr [biHeight]; в cx высота изображения в пикселяхCurY,cx; поскольку строки изображения в BMP расположены наоборот, то начинаем рисовать снизу вверх!CurX,0; начиная с первого правого пикселя изображенияCalculatePar; вызываем ф-ию для вычисления кол-ва битов, не принадлежащих изображению, но добавленных для выравнивания

; теперь IgnoredBits равно числу игнорируемых битов при рисовании

; будем читать из файла растр блоками по BlockSize байт и записывать в Rastr

; цикл для чтения из файла блоков растра:Rastr, BlockSize; читаем блок растра из файлаReadFileError; если ошибка доступа, то сообщаемax,0; если достигнут конец файла _Skip; _ то выходим из циклаDrawBlock; обработка блокаax,cx; если это был последний блок, то _Skip; _ выходим из файлаReadBlock; читаем следующий блок:CloseFile; закрываем файлah,00; ф-ия для ожидания нажатия клавиши16h; ждем пока юзер не нажмет любую клавишу, а затем выходим

; восстановим предыдущий видеорежимah,ah; ah=0 - ф-ия для установки графического режимаal,OldScreenMode; установка предыдущего режима10h; устанавливаем графический режим с помощью прерывания BIOSax,4C00h21h; выход из программы:; у изображения слишком большой размер (больше чем 320x200)CLoseFileEMsg5:; вывод сообщения об ошибке, в случае возникновения ошибки чтенияEMsg4Begin

; Функция для закрытия файла

; ВХОД: sp должен указывать на дескриптор файла:

; закрытие файлаah,3eh; 3eh - ф-ия DOS для закрытия файлаbx,Descriptor21h; закрыть)

; ф-ия для отрисовки одного пикселя

; Вход: al= индекс палитрыprocdx; сохраним dx в стек, чтоб не испортить

; если CurX указывает на бит, который не входит в изображение, то пропускаем рисованиеcx,word ptr [biWidth]; в cx - ширина изображенияcx,CurX; если текущий рисуемый пиксель выходит за границы изображения _SkipDraw; _ то пропускаем рисованиеCurX,319SkipDrawCurY,199SkipDraw

; рисуем точку

; mov cx, CurX; номер колонки - текущий (CurX)

; mov dx, CurY; номер строки - текущий (CurY)

; mov ah,0ch; 0ch - ф-ия для рисования точки в видеосервисе BIOS

; mov bh,0; номер видеостраницы = 0

; int 10h; рисуем точку

; рисуем точкуax; сохраним ax чтоб не испортитьax,320; найдем расположение нужного байта в памяти видеобуфераCurY; умножим на номер строкиax,CurX; прибавим номер колонкиdi,ax; es:di указывает на байт, соответствующий данному байтуax; восстановим значение индекса палитрыbyte ptr es:[di],al; копируем индекс палитры данного пикселя в видеобуфер:

; проверка достижения конца строки изображенияCurX; переходим на следующий пиксельcx,word ptr [biWidth]; в cx - ширина изображенияcl,IgnoredBits; прибавляем к ней кол-во битов, которые не должны отрисовыватьсяCurX,cx; если текущий номер пикселя не равен последнему _SkipEqu; _ то пропускаем переход к следующей строке:

; переход на след. строкуCurX,0; теперь номер 1ого пикселя - нулевойCurY; CurY - указывает следующую строку:dx; восстановим dxendp

; ф-ия для установки видеорежима и цветов палитры.procah,0Fh; ф-ия BIOS для получения номера текущего видеорежима10hOldScreenMode,al; сохранитьah,ah; ah=0 - ф-ия для установки графического режимаal,13h; al=13h установка режима 320x200 c 256 цветами10h; устанавливаем графический режим с помощью прерывания BIOSdx,3c8h; порт видео палитры (3C8h)al,0; установить индекс палитрыdx,al

; Установить цвет фона в черный

; (0,0,0) - черныйdx,3c9h; порт 3C9hal,0; красныйdx,alal,0; зеленыйdx,alal,0; синийdx,aldx,3c8h; порт видео палитры (3C8h)al,1; установить индекс палитры 1dx,al

; сделаем белый цвет (63, 63, 63)dx,3c9h; порт записи 3C9hal,63; красныйdx,alal,63; зеленыйdx,alal,63; синийdx,alendp

; процедура для обработки блока растра

; вход: в регистре ax - размер данных в блоке

;по адресу Rastr располагается битовый массив растраproc

; сохраним значения регистров в стеке, чтоб ничего не попортитьaxbxcxdxsi,Rastr; si указывает на нулевой байт в массиве растраcx,ax; теперь в cx кол-во байтов растра в данном блоке

; циклическая обработка каждого байта растра в блоке:cx; сохраняем количество итераций в стекеdl,[si]; копируем текущий байт в регистр dlDrawByte; вызываем ф-ию отрисовки байта растраsi; переходим к следующему байтуcx; восстанавливаем значение счетчика итерацийBCycle; выполняем цикл, пока не обработаем все байты

; восстановим регистрыdxcxbxaxendp

; процедура для отрисовки пикселей, записанных в одном байте

; вход: dl - байт для отрисовкиprocbl,10000000b; в bl - маска для выборки первого слева битаcx,8; количество итераций = количеству бит в байте

; будем сдвигать маску вправо и вычленять значения битов с помощью логического И:cx; сохраним значение счетчика итерацийdl,bl; логическое И между нашим байтом и маской. результат - изменение флаговWhite; если бит=1, то цвет пикселя белыйal,0; если нет, то черныйSkipColor; пропускаем установку цвета в белый:al,1; al=1. 1 - индекс палитры для белого цвета (см. SetDisplay):DrawPixel; рисуем данный пиксель на экранеbl,1; сдвигаем маску вправоcx; восстановить счетчик циклаShrCycle; выполняем алгоритм для каждого битаendp

; ф-ия для вычисления количества игнорируемых битов в строке растра. (они добавляются для выравнивания строки по параграф)

; вход: -

; выход: IgnoredBitsproc

; сохраним на всякий случай значения регистров в стекaxcxdxbxax,word ptr [biWidth]; в ax - ширина изображенияbl,32; будем делить на 32. Откуда 32? (biWidth/8)/4 == biWidth/32. Ненулевой остаток от деления говорит о необходимости выравниванияcx,cx; cx=0 - здесь будет храниться число добавляемых бит для выравнивания

;будем выполнять деление, смотреть остаток:bl; делим на 32 ширину изображенияah,0; если остаток равен нулю, то _ExitCycle; _ выходим из циклаcx; если остаток ненулевой, то добавляем 1 бит для выравнивания и снова делимax,word ptr [biWidth]; в ax - первоначальная ширина изображенияax,cx; теперь в ax - расширенный дополнительными битами размер строки изображенияCalcCycle; снова делим, пока не дополним строку до кратности 4:IgnoredBits,cl; сохраним количество битов, дополняющих строку до параграфа

; восстановим все регистрыbxdxcxaxendp

; Процедура для парсинга строки параметров

; Вход: es ссылается на префиксный сегмент (PSP)

; Выход: dh содержит кол-во символов в имени файла, считываемого (имени) из параметров командной строки

; Также влияет на глобальную переменную I_Option, устанавливает ее в 0 или 1, в зависимости от того, установлена ли опция /Iprocbx,80h; в bx - смещение строки параметров программы относительно префиксного сегментаdx,dx; dx=0dl,es:[bx]; в dl - кол-во считанных символов из командной строкиbxdl,dl; если параметров нет, то _SkipParsing; _ парсить нечегоdi,fname; в di смещение на строку, которая будет хранить имя файлаcx,cx; cx=0cl,dl; в счет цикла (cx) помещаем кол-во символов в строке параметровdi,2; сделано для совместимости формата строки при вводе имени файла через параметры и при вводе с клавиатуры:al,es:[bx]; в al пересылаем текущий символ из строки параметров в PSPal,''; если полученный символ - пробел, _NextSymbol; _ то игнорируем его и переходим к следующемуal,'/'; если символ - косая черта, что обозначает использование опции, _UseOption; _ то переходим на метку обработки опции[di],al; если обычный символ - просто переписываем его в fnamedi; на следующую позицию в fname!dh; увеличиваем счетчик записанных символовNextSymbol; переход к следующему символу:cx; поскольку будем анализировать след. символ, то уменьшим счетчикEndCopy; если косая черта была последней в строке, то завершаем работу со строкой, опция - игнорируетсяbx; переходим к след. символуal,es:[bx]; пересылаем его в alal,'I'; если это не ключ нашей опции игнорирования, а нечто иное _NextSymbol; _ то просто переходим к след. символуI_Option,1; если /I, то включаем опцию:bx; Переход к след. символуCopySymbols:[di],0; строку завершаем нулем, чтоб DOS мог нормально ее считать при открытии файла:endpstart


Результат работы программы

 

Рисунок 1. при запуске программы необходимо ввести директорию файла *.bmp

 

Рисунок 2. После ввода правильной директории файла программа рисует изображение

 


Заключение

 

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

В данной курсовой работе рассмотрены основные этапы программирования на ассемблере, реализован алгоритм выполнения поставленной задачи.

ассемблер файл машинный программа


Список используемой литературы

1. В.Н. Пильщиков. Программирование на языке ассемблера IBM PC. - М.: Диалог - МИФИ. 1997

. Ярмиш Р., Ярмиш Дж. - Основы программирования на языке Ассемблера

. А. Крупник - Изучаем Ассемблер. 2004

. П. И. Рудаков, К. Г. Финогенов - Язык ассемблера: уроки программирования. 2001

. Виктор Юров - Assembler. Практикум. 2004



Поделиться:




Поиск по сайту

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2020-04-01 Нарушение авторских прав и Нарушение персональных данных


Поиск по сайту: