|
|
|
Wowa |
|
|||
Эксперт Профиль Группа: Админ Сообщений: 15017 Регистрация: 14.9.2000 Где: Винград Репутация: нет Всего: 290 |
Посоветуйте что-нибудь.
|
|||
|
||||
Fantasist |
|
|||
Лентяй Профиль Группа: Участник Клуба Сообщений: 1517 Регистрация: 24.3.2002 Репутация: нет Всего: 41 |
Chingachguka! Chingachguka на сцену. Пусть дла начала свои уроки запостит.
-------------------- Волны гасят ветер... |
|||
|
||||
Vit |
|
|||
Vitaly Nevzorov Профиль Группа: Экс. модератор Сообщений: 10964 Регистрация: 25.3.2002 Где: Chicago Репутация: нет Всего: 207 |
Это точно, начинать надо с Chingachguka
-------------------- With the best wishes, Vit I have done so much with so little for so long that I am now qualified to do anything with nothing Самый большой Delphi FAQ на русском языке здесь: www.drkb.ru |
|||
|
||||
neutrino |
|
|||
Gothic soul Профиль Группа: Модератор Сообщений: 3041 Регистрация: 25.3.2002 Где: Верхняя Галилея, Кармиэль Репутация: нет Всего: 62 |
Est takaia bolshaia kniga Toma Svana (Tom Swan) nazivaetsia "programmirovanie v Turbo Assembler". Ochen podrobnoe opisanie. Kucha primerov i poniatno napisannaia.
Rekomenduiu. -------------------- The truth comes from within ... Покойся с миром, Vit |
|||
|
||||
Chingachguk |
|
|||
Эксперт Профиль Группа: Участник Клуба Сообщений: 1232 Регистрация: 25.3.2002 Где: Москва Репутация: 11 Всего: 18 |
О ! Всем привет ! ))
Так что, можно продолжить ?! Оки ! Ниже пошел первый Урок. -------------------- I don't like the drugs (but the drugs like me). M.Manson. |
|||
|
||||
Chingachguk |
|
|||
Эксперт Профиль Группа: Участник Клуба Сообщений: 1232 Регистрация: 25.3.2002 Где: Москва Репутация: 11 Всего: 18 |
Урок 1. Немного порисуем.
Итак, начнем. Запустите tp7(или более младшие версии, где можно писать asm end; - и компиллер не ругнется). Tp7 Вы можете взять тут(~550Кил): http://chat.ru/~vzubko/tp7.zip Наберите следующий код: begin {Устанавливаем графический режим монитора 13h, 320x200, 256 цветов} asm mov ax,0013h int 10h end; asm mov ax,0A000h mov es,ax {Рисуем - раз} mov byte ptr es:[320*10+10],12 mov byte ptr es:[320*10+11],12 mov byte ptr es:[320*10+12],12 mov byte ptr es:[320*11+10],12 mov byte ptr es:[320*11+11],12 mov byte ptr es:[320*11+12],12 mov byte ptr es:[320*12+10],12 mov byte ptr es:[320*12+11],12 mov byte ptr es:[320*12+12],12 {Рисуем - два} mov byte ptr es:[320*100+100],1 mov byte ptr es:[320*101+101],2 mov byte ptr es:[320*102+102],3 mov byte ptr es:[320*103+103],4 mov byte ptr es:[320*104+104],5 mov byte ptr es:[320*105+105],6 end; {Ожидаем нажатия клавиши} asm mov ah,0 int 16h end; {Устанавливаем текстовый режим монитора 03h, 80x25, 16 цветов текста и фона} asm mov ax,0003h int 10h end; end. Ага. Теперь скомпиллируйте ЭТО и запустите на выполнение. Что Вы видите ? (Должны увидеть квадратик и цепочку точек). Нажав клавишу, Вы должны закрыть графическое окно и вернуться в среду. НЕбольшое техническое отступление. Синтаксис асм-вставок в tp7. Асм-вставка начианется псевдооператором "asm". Далее идут сами ассемблерные команды(Вы должны видеть их зелеными). Завешает блок асм директива "end;" - как, врочем, и другие логически завершенные блоки в Pascal. Теперь посмотрим на команды. Их не так много и они довольно одинаковы. Отбросим пока вот эти три блока, дав им поверхностное объяснение: asm mov ax,0013h int 10h end; Пока примите, как факт, что для вызова Операционной системы, BIOS или других программ обычно используются вот такие вот записи(команды): mov ax,0013h - это пример ЗАДАНИЯ ПАРАМЕТРОВ, передаваемых другим программам; int 10h - это ВЫЗОВ других программ Вашей машины - здесь это вызов BIOS. {Ожидаем нажатия клавиши} asm mov ah,0 int 16h end; mov ah,0 - это пример ЗАДАНИЯ ПАРАМЕТРОВ, передаваемых другим программам; int 16h - это ВЫЗОВ других программ Вашей машины - здесь это вызов BIOS. Итак, вернемся к тем командам, которые откомментарены как " {Рисуем - раз}" и "{Рисуем - два}". Попытайтесь понять, чем они похожи, а чем отличаются... ... Вы должны были заметить, что вот эти команды: mov byte ptr es:[320*10+10],12 mov byte ptr es:[320*10+11],12 ... в более общем виде можно записать как: mov byte ptr es:[Что-то],Еще что-то. Попробуйте самостоятельно поменять эти "Что-то" и "Еще что-то" у нескольких команд. Посмотрите на результат. Создайте еще несколько подобных команд. Проявите фантазию в разумных пределах и насоздавайте еще разных подобных команд. Попытайтесь сделать самостоятельно какие-то обобщения по результатам. А теперь небольшое задание. Исходный пример рисовал нам красный квадратик в верхнем левом углу экрана. Попробуйте на основе полученного опыта ТОЛЬКО с помощью команд типа: mov byte ptr es:[Что-то],Еще что-то. нарисовать синий прямоугольник, но уже в нижнем правом углу экрана. Подсказка: обратите внимание вот на этот комментарий: {Устанавливаем графический режим монитора 13h, 320x200, 256 цветов} Урок 1 закончен. Решение и некоторые объяснения будут даны в уроке 2. Да пребудет с Вами Великая Сила ! -------------------- I don't like the drugs (but the drugs like me). M.Manson. |
|||
|
||||
Chingachguk |
|
|||
Эксперт Профиль Группа: Участник Клуба Сообщений: 1232 Регистрация: 25.3.2002 Где: Москва Репутация: 11 Всего: 18 |
Урок 2. Основные понятия. Микропроцессор 8086. Решение примера Урока 1
на основе полученных знаний. Косвенная адресация: первый пример. Итак, начнем этот урок с очень важной штуки. Введем основные определения, которых будет немного, они будут просты... но это будут самые важные понятия во всем этом деле ! Итак, чего вообще мы хотим ? Мы хотим научиться разговаривать с Машиной на ее языке. Поэтому дадим понятие КОМПЬЮТЕРА(Машины), именно так, как она будет выглядеть для Вас при программировании на ассемблере: МАШИНА - нечто, состоящие из ПРОЦЕССОРА, ОПЕРАТИВНОЙ ПАМЯТИ и ПОРТОВ ВВОДА-ВЫВОДА. ПРОЦЕССОР умеет выполнять ПРОГРАММЫ. Раскроем детальнее эти понятия: - ОПЕРАТИВНАЯ ПАМЯТЬ: набор ячеек, в котрые можно записывать числа и из которых можно читать числа. - ПОРТЫ ВВОДА-ВЫВОДА: набор ячеек, в котрые можно записывать числа и из которых можно читать числа. - ПРОЦЕССОР: функция, понимающая и реализующая числа, записанные в ОПЕРАТИВНОЙ ПАМЯТИ как действия (КОМАНДЫ). Выполнение команд назовем ПРОГРАММОЙ. Итак, это важно !!! - нет никаких жестких дисков, джойстиков, мышей ... Есть только ПРОЦЕССОР, ОПЕРАТИВНАЯ ПАМЯТЬ и ПОРТЫ ВВОДА-ВЫВОДА. Любое наше действие будет направлено ТОЛЬКО на работу с этими тремя объектами. Итак, мы определились: есть ОПЕРАТИВНАЯ ПАМЯТЬ, в ней храняться числа, ПРОЦЕССОР обрабатывает эти числа и выполняет действия, заданные этими числами. Очевидно из данных нами определений, что эти действия(КОМАНДЫ) в любом случае могут быть направлены ТОЛЬКО на измение(чтение/запись) ОПЕРАТИВНОЙ ПАМЯТИ и (или) ПОРТОВ ВВОДА-ВЫВОДА, либо на изменение состояния самого ПРОЦЕССОРА. В общем виде КОМАНДУ можно представить в таком виде: Что_Делать:<Как Делать>. Как_Делать может быть пропущенно(<...>), ибо Что_Делать: ничего не делать не требует дополнительных сведений. Да, есть такая команда - Ничего_Не_Делать. Пример из жизни: команда "Лежать" также не требует дополнительных данных. Таким образом, процессор читает ОПЕРАТИНВУЮ ПАМЯТЬ и трактует прочитанные числа как команды. Поняв команду, он выполняет заданные в ней действия. Команды, как уже было сказано, могут сводится к одному или нескольким из следующих действий: - Ничего не делать; - Изменить что-то в ОПЕРАТИВНОЙ ПАМЯТИ; - Изменить что-то ПОРТАХ; - Изменить состояние процессора. Что значит "Изменить что-то в оперативной памяти" ? Это означает изменить те числа, которые в ней находятся: прочесть их или записать новое значение числа. То же самое и с портами ввода-вывода. Что означает "Изменить состояние процессора" ? Это означает повлиять на то, как он будет трактовать(исполнять, выполнять) КОМАНДЫ. Вернемся к второй части КОМНАДЫ - "Как Делать". Очевидно, что в ней должно содержаться указание на область ОПЕРАТИВНОЙ ПАМЯТИ, если мы хотим ее читать/записывать, либо указание на область ПОРТОВ, если мы хотим читать/записывать в них. Поэтому введем понятие ЭФФЕКТИВНОГО АДРЕСА - указатель на конкретный элемент памяти, портов или процессора. Теперь хватит теории, перейдем к практике. Мы работали в Уроке 1 и будем работать в ближайшее время с конкретным процессором - 8086 фирмы Intel, выпущенным еще в конце 70-х годов. Процессор этот выполняет команды, записанные в опеределенного вида памяти, и может, выполняя команды, изменять определенного вида порты ввода-вывода. Память эта также есть набор ячеек, в которые можно записывать числа. Каждая ячейка может хранить числа от 0 до 255. Порты также являются ячейками, в которые можно записывать /из которых можно читать числа от 0 до 255. Как храняться числа в этих ячейках ? Каждая из них состоит из 8 так называемых бит. Бит - это нечто, могущее быть только в двух состояниях - 0/1(Да/Нет,Триггер ... - как Вам нравиться). Вспомним, что любое целое и неотрицательное число (0,1,2..10000...) можно разложить по степеням двойки: 25 = 16+8+1 = 1*2^4 + 1*2^3 + 0*2^2 + 0*2^1 + 1*2^0 = 1*16+1*8+0*4+0*2+1*1. Итак, если мы будем трактовать 8 бит каждой такой ячейки, называемой байтом, как коэффициенты при степени двойки, то получим возможность раскладывать числа по 8-ми различным степеням: 2^7,2^6... 2^0. Иначе говоря, каждое число в каждой ячейке оперативной памяти 8086 реализовано определенным состоянием всех восьми бит этой ячейки: Число: 25 65 128 255 Бит0 1 1 0 1 Бит1 0 0 0 1 Бит2 0 0 0 1 Бит3 1 0 0 1 Бит4 1 0 0 1 Бит5 0 0 0 1 Бит6 0 1 0 1 Бит7 0 0 1 1. Каждая такая ячейка называется байтом. Итак, в 8086 записываются числа в оперативную память. Процессор может читать эти числа, трактовать их как команды, понимать из команды, какую ячейку памяти ему нужно изменять. Как же он это делает ? Очевидно, что ему надо знать ЭФФЕКТИВНЫЙ АДРЕС команды, ЭФФЕКТИВНЫЙ АДРЕС ячейки, которую указано поменять в ПАМЯТИ или ПОРТАХ. По большому счету, ЭФФЕКТИВНЫЙ АДРЕС - это номер ячейки(номер байта) в памяти или портах. Нумерация от нуля. Например, байт(ячейка) номер 20 содержит значение 22. Как же процессор формирует этот ЭФФЕКТИВНЫЙ АДРЕС ? (Иными словами, где хранится и как вычисляется номер байта) ? Как ни странно, но он делает это весьма замысловатым образом: в процессоре имеются так называемые РЕГИСТРЫ - это тоже ячейки "памяти" самого процессора, но размером в СЛОВО(два байта). Можно сказать, что у Процессора есть своя небольшая память, состоящая из набора слов. Если байт - это ячейка из восьми бит, то слово содержит целых 16 бит, и в него можно записывать числа от 0 до 65535(посмотрите, как хранятся числа в ячейках-байтах и поймите, какие числа можно хранить в ячейках из 16 бит). Имея около десятка таких ячеек-слов, процессор использует некоторые из них для вычисления ЭФФЕКТИВНОГО АДРЕСА. Вы можете подумать, что номер ячейки памяти, содержащую текущую выполняемую команду, просто храниться в одном из РЕГИСТРОВ, а после выполнения текущей команды в него заносится номер следующей команды: Команда1 Байт1, Байт2,Байт3 команды 1. Номер ячейки - 230 (Номер байта1). Регистр_Текущей_Команды равен 230. После выполнения команды1 процессор начнет выполнять команду2: Команда2 Байт1, Байт2 команды 2. Номер ячейки - 233 (Номер байта1). Регистр_Текущей_Команды равен 233 ? В какой-то мере у процессора 8086 это так, но в точности - не так ! Скажем вот что: процессор 8086 может работать с памятью размером в один Мегабайт(примерно миллон ячеек по одному байту). Команды или какие-то вспомогательные числа могут быть размещены в любой ячейке с номером от 0 до ~1 миллиона. Т.е. номер текущей выполняемой команды может быть в этом диапазоне. Процессор может использовать для хранения этого номера один или несколько из своих регистров размером в слово. Вот эти регистры, которые есть у него(все они размером в слово): Сокращенное имя/Полное имя IP - Instruction Pointer; CS - Register of Code Segment; SS - Register of Stack Segment; SP - Stack Pointer; ES - Register of Extra Segment; DS - Register of Data Segment; AX - Accumulator; BX - Base Register; CX - Counter DX - Data Register; SI - Source Register; DI - Destination Register; BP - Base Pointer; FLAGS - Flags Register. Итак, имеем этот набор регистров. Каждый размером в слово. Не обращайте пока внимание на их названия. Прикинте, как процессор хранит номера ячеек памяти в них. Вы могли догадаться, что для хранения номера ячейки недостаточно любого одного регистра из-за того, что размер памяти 8086 = 1 миллион > максимальное число, которое можно хранит в одном слове - 65535. Два будет абсолютно достаточно, ибо число ~один миллион легко раскладывается по степеням двойки вплоть до 20 степени, а, значит, нам достаточно иметь всего 20 бит для его хранения ... А два регистра обладают уже 32 битами. Например, можно придумать такую схему размещения номера байта(ЭФФЕКТИВНОГО АДРЕСА) в двух регистрах: 1-ый регистр - 16 младших(первых) битов числа ЭФФЕКТИВНОГО АДРЕСА; 2-ой регистр - 4 старших(вторая часть) битов. Но это не так !!! Вот что делает этот хитрый процессор: он использует действительно два регистра, но значение одного из них он умножает на 16 и к полученному значению прибавляет значение из другого регистра или самой команды непосредственно: ЭФФЕКТИВНЫЙ АДРЕС = Регистр1 x 16 + Регистр 2(или непосредственное значение). Возьмем команду из Урока 1: mov byte ptr es:[320*10+10],12 Эта команда предназначена для того, чтобы записать в ячейку памяти номер 658570 числа 12. Смотрите, что в этой команде задано: Что_Делать: Записать число в память. Как Делать: Число взять из самой команды - 12; Адрес памяти вычислить, используя регистр es и непосредственное значение, указанное в команде - 320*10+10; Размер применика(числа в памяти для записи) - один байт. Сейчас обратим внимание ТОЛЬКО на то, как 8086 ухитрился вычислить адрес ячейки памяти из этой команды. Смотрите: Регистр1 = Регистр ES(в команде так и задано) Непосредственное значение для прибавки = 320*10+10 (тоже задано в команде) ЭФФЕКТИВНЫЙ АДРЕС = ES x 16 + 320*10+10 = 658570. Кто же задал значение регистра ES Ясно дело, что мы ! Мы контролируем весь процесс выполнения программы процессором ! А как мы это сделали ? А вот как: mov ax,0A000h mov es,ax Мы тут задали значение регистра ES - 0A000h = 40960. Теперь Вы понимаете, что меняя "Что-то" в командах Урока1: mov byte ptr es:[Что-то],Еще что-то вы меняли Адрес Ячейки Памяти ! А вот решение задания: mov byte ptr es:[320*160+110],9 mov byte ptr es:[320*160+111],9 mov byte ptr es:[320*160+112],9 mov byte ptr es:[320*161+110],9 mov byte ptr es:[320*161+111],9 mov byte ptr es:[320*161+112],9 mov byte ptr es:[320*162+110],9 mov byte ptr es:[320*162+111],9 mov byte ptr es:[320*162+112],9 - синий квадратик. Сейчас у Вас должно возникнуть еще больше вопросов, нежели после первого урока !!! Но и должно появиться смутное ощущение ПАМЯТИ, которой Вы можете управлять такими вот командами. А теперь - на закуску - Косвенная адресация !!! Уже было сказано, как 8086 может вычислять адрес в памяти: ЭФФЕКТИВНЫЙ АДРЕС = Регистр1 x 16 + Регистр 2(или непосредственное значение). Только что мы видели, как он использует непосредственное значение, взятое из команды. А теперь поглядите, как можно заставить процессор использовать второй вариант - через использование двух регистров: mov bx,320*180+100 {Заносим значение(число) 320*180+100 в регистр BX} mov byte ptr es:[bx],2 {Изменим память, используя ДВА регистра для адресации} В последней команде эффективный адрес будет вычислен так: ЭФФЕКТИВНЫЙ АДРЕС = ES x 16 + BX. Теперь попробуйте использовать для рисования комнады, использующие такой способ адресации, например: {Рисуем - три !!!} asm mov bx,320*180+100 {Заносим значение(число) 320*180+100 в регистр BX} mov byte ptr es:[bx],2 {Изменим память, используя ДВА регистра для адресации} mov bx,320*180+101 {Заносим значение(число) 320*180+101 в регистр BX} mov byte ptr es:[bx],2 {Изменим память, используя ДВА регистра для адресации} mov bx,320*180+102 {Заносим значение(число) 320*180+102 в регистр BX} mov byte ptr es:[bx],2 {Изменим память, используя ДВА регистра для адресации} end; Если Вы выполните этот код, то должны увидеть маленькую зеленую полоску внизу и посередине экрана. Задание: попробуйте сделать эту полоску потолще и подлиннее, но используя именно такие команды - mov byte ptr es:[bx]. Попытайтесь вместо таких команд использовать уже известные Вам - типа mov byte ptr es:[320*180+100],2. Урок 2 закончен. Некотрые объяснения будут даны в уроке 3, но вопросов должно быть немеряно !!! Да пребудет с Вами Великая Сила ! -------------------- I don't like the drugs (but the drugs like me). M.Manson. |
|||
|
||||
AXEL3323 |
|
|||
Unregistered |
Привет!! Уроки - просто супер! Вот у меня вопрос
В пакете Tasm в отладчике td.exe для отладки существует много способов (пошаговые, бреакпоинтовский и т.д.), для краткости это F4,F7,F8, ну и F9. Так вот чтобы прервать выполнение программы надо нажать сочетание Ctrl+F2 ( Program Reset). НО в режиме отладки F9 программа не останавливается . Так надо??..Что-то я не пойму... А отладчик версии 5.0 ( от 21.02.96), я его взял с нового диска , хотя с тех пор он и не менялся....(ну я имею ввиду 16-разрядный из TASM'а) Так как мне прервать выполнение программы?(из режима RUN) |
|||
|
||||
neutrino |
|
|||
Gothic soul Профиль Группа: Модератор Сообщений: 3041 Регистрация: 25.3.2002 Где: Верхняя Галилея, Кармиэль Репутация: нет Всего: 62 |
Tut mnogo, kto hochet asm uchit. Mojet Chingachguku otdelnuiu formu sdelat? S temami ... Ia bi, naprimer, zahjodil. I primeri interesnie daet. Mojet knigu vipustit "Assembler Chingachguka". Vot eto tochno ne lamievo!
-------------------- The truth comes from within ... Покойся с миром, Vit |
|||
|
||||
Chingachguk |
|
||||
Эксперт Профиль Группа: Участник Клуба Сообщений: 1232 Регистрация: 25.3.2002 Где: Москва Репутация: 11 Всего: 18 |
Из режима RUN можно использовать CTRL_BREAK. Но ! Если, к примеру, в программе написать замкнутный цикл: @@Label: jmp @@Label То нажатие этих клавиш не всегда прервет программу внутри этого кода Потому, что еще выполняются прерывания ... Отладчик может остановить работу программы двумя способами: установить свой обработчик на клавиатуру(это и есть CTRL_BREAK), но бывает код, вырубающий прерывания/маскирующий прерывания от клавиатуры, а также установить брейкпойнты (это и есть F4...). Видимо, ты пытаешься отладить программу, которая, к примеру, где-то виснет и ты хочешь, нажав CTRL_F2, ее скинуть, узнав где она зависла ? Рекомендую действовать методом приближения к "багу": устанавливаешь брейки и постепенно доходишь до неверного кода.
Хе, да я в жизни ничего подобного не делал, у меня даже своей странички нету Хотя, может быть, дойдут руки... К тому же я счас помогаю развивать вот этот сайт http://hi-tech.nsys.by/ - он целиком по асму. -------------------- I don't like the drugs (but the drugs like me). M.Manson. |
||||
|
|||||
neutrino |
|
|||
Gothic soul Профиль Группа: Модератор Сообщений: 3041 Регистрация: 25.3.2002 Где: Верхняя Галилея, Кармиэль Репутация: нет Всего: 62 |
Da, sait nichego, osobenno fanariki na solnechnih batareikah ponravilis. No dolgo gruzitsia.
-------------------- The truth comes from within ... Покойся с миром, Vit |
|||
|
||||
Chingachguk |
|
|||
Эксперт Профиль Группа: Участник Клуба Сообщений: 1232 Регистрация: 25.3.2002 Где: Москва Репутация: 11 Всего: 18 |
Урок 3. Продолжаем работать с памятью. Первый цикл. Изучение
двухкомпонетного адреса. Упс, как говорит Б.Спирс, ай дид ит эгейн. Ну и мы тоже эгейн. В смысле, снова поработаем с памятью. Итак, память. Памяти у нас примерно миллион ячеек по 1 байту. Где-то находятся байты нашей программы, которую процессор сейчас читает байт за байтом и выполняет, где-то байты программ БИОС-а, где-то - ДОС-а. Ну а начиная с байта нумер 655360 находится так называемый видеобуфер. Можно сказать по-другому - с номера A0000h. Это - шестнадцетеричная система исчисления. Эти числа равны: 655360=A0000h, просто они записаны по-разному. Здесь мы не будем подробно разбирать эту систему, приведем только пример преобразования числа A0000h в "нормальный" вид: A0000h = A*16^4+0*16^3+0*16^2+0*16^1+0*16^0 = 10*16^4 = 655360. h - просто обозначение такой системы исчисления; A = 10, B = 11, C = 12, D = 13, E = 14, F = 15 - поскольку основанием является 16, то для записи числа НЕ ХВАТАЕТ чисел "привычной" десятичной системы - 0,1,2,3..9. Вы вполне можете обойтись виндовым или любым другим калькулятором для такого рода преобразований. Ага, так что же такое видеобуфер ? Он же - видеопамять, видеокарта, ... Для нас нет никаких железок, джемперов, жестких дисков, повторяю ! Есть только память, порты и процессор. Видеобуфер для нас в данном случае - просто КУСОК ПАМЯТИ. Начинается с байта номер A0000h. Почему же мы выделяем этот кусок особо ? А вот почему: помните, у нас в Уроке 1 был такой код: {Устанавливаем графический режим монитора 13h, 320x200, 256 цветов} asm mov ax,0013h int 10h end; Всего две команды, а делают сколько ! После их выполнения БИОС сделает так, что всякая запись чисел в этот видеобуфер приведет к изменениям на мониторе ! Как это происходит ? С нашей стороны "забора" мы пишем в ячейки этого куска памяти числа. Они там и остаются, пока их не изменить. С другой стороны "забора" сидит аппаратура, "железо", как ее еще называют, которая СОВЕРШЕННО НЕЗАВИСИМО от выполнения наших программ начинает трактовать эти числа КАК ЦВЕТА ТОЧЕК монитора. Это ее БИОС так заставил делать. Переключил в такой режим. Бывают и другие режимы работы видеокарты-видеоаппаратуры - текстовые там, графические ... Мы в графическом. Но это все нам неважно. Важно нам только то, как надо писать в эту память числа, чтобы аппаратура эта нарисовала на их основе изображение на мониторе. Более детально. Вспомним, что режим у нас - 320x200, 256 цветов. 320 точек по горизонтали, 200 - по вертикали. Каждая точка может иметь 256 различных цветов. 1 байт памяти как раз может иметь 256 различных состояний. Число в байте номер A0000h аппаратура трактует как цвет верхнего левого пикселя, число в следующем байте - как цвет следующего(двигаясь направо) пикселя и так далее. На одну строчку 320 пикселей - значит, и в памяти 320 байт. 321 байт начиная с байта A0000h - это уже самый левый пиксель второй стороки и так далее: Номер пикселя по горизонтали/вертикали - номер байта в памяти 0 1 2 3 0 A0000h A0000h+1 A0000h+2 A0000h+3 ... 1 A0000h+320... 2 ... Ага. Нетрудно сообразить, что для всех 320x200 точек монитора требуется 320x200 = 64000 байт памяти. Например, запись в байт с номером A0000h+320x200-1 приведет к изменению цвета нижнего правого пикселя. Проверим это. Нарисуем вертикальную горизонтальную линию на мониторе, желтого цвета, по самой первой строке от левого до правого края монитора. От уха до уха, так сказать. Для этого мы должны записать число 14(желтый цвет) в байты с номерами A0000h,A0000h+1... A0000h+319 - всего 320 последовательных байт. Вспоминаем, как процессор может делать это: mov ax,0A000h {Заносим в регистр AX число 0A000h} mov es,ax {Копируем число из регистра AX в регистр ES, фактически - 0A000h} mov byte ptr es:[0],14 {Записываем по адресу 0A000hx16+0 байт значением 14} mov byte ptr es:[1],14 {Записываем по адресу 0A000hx16+1 байт значением 14} mov byte ptr es:[2],14 {Записываем по адресу 0A000hx16+2 байт значением 14} ... Не надоело ? Верно, надо делать цикл. Как и в других языках программирования, в асме тоже есть циклы. Что же за цикл нам нужен ? Цикл из 320 повторений, в цикле должен вертеться индекс, позволяющий нам записывать СМЕЩЕНИЕ адреса в команде от 0 до 319. СМЕЩЕНИЕ - это та часть эффективного адреса, который процессор вычисляет из команды и добавит его к СЕГМЕНТНОМУ регистру, умноженному на 16: mov byte ptr es:[1],14 Эффективный адрес = es * 16 + 1 СЕГМЕНТНАЯ ЧАСТЬ СМЕЩЕНИЕ. В этой команде смещение указано явно. Жестко. Сколько бы раз мы не выполнили эту команду, она запишет байт 14 в одну и ту же ячейку памяти. Если только не менять значение сегментного регистра es. Почему бы нам не поменять его ? А вот, например, почему: нетрудно заметить, что ЛЮБОЕ значение в сегментном регистре es при смещении = 1 нам НИКОГДА не позволит писать в ячеку памяти номер A0000h(подумайте, почему !. Теперь вспомним, что в Уроке 2 мы проходили так называемую КОСВЕННУЮ адресацию: mov bx,1 mov byte ptr es:[bx],14 {Записываем по адресу 0A000hx16+bx байт значением 14}. Процессор использовал для получения смещения регистр ! А регистры мы можем менять ! Тогда начнем писать цикл: mov ax,0A000h {Заносим в регистр AX число 0A000h} mov es,ax {Копируем число из регистра AX в регистр ES, фактически - 0A000h} mov bx,0 {Смещение первой точки равно 0} mov byte ptr es:[bx],14 ADD bx,1 {Добавить к регистру BX 1 !} Вот, новая команда(ADD) ! До сих пор мы работали с одной командой засылки значения - mov(от move, англ.). А команда "ADD" (addition, сложить) позволяет добавлять к приемнику операции (здесь - регистр BX) значение источника - "1". И регистр BX станет равен 1 ! Что же дальше ? Последуем классическому типу циклов: repeat {Тело цикла} Until {Условие=TRUE} Очевидно, что телом цикла у нас выступает команда закраски - mov byte ptr es:[bx],14. Командой add bx,1 мы изменили регистр BX и можем анализировать его состояние (Условие=TRUE). Что же мы будем анализировать ? Если мы хотим задать смещение от 0 до 319, то нам годятся все значения bx в этом диапазоне, иначе цикл надо прерывать. Делаем это: add bx,1 {inc(BX) или BX:=BX+1 или BX++} CMP bx,319 {Сравнить BX и 319} JBE МЕТКА_НАЧАЛА_ЦИКЛА - @repeat. Опять, опять новые команды ! Не бойтесь, их вообще не так много, а выучить их проще простого ! Я обязательно далее раскажу подробно о командах, а пока лишь вкратце: CMP bx,319 {COMPARE BX WITH 319} JBE @repeat {JUMP IF BELOW OR EQUAL} Вы видите расшифровку сокращений этих команд. CMP-это сравнение. BX с 319. По результатам этого сравнения мы можем писать команды переходов. А фактически - приказать процессору перейти на конкретную команду, да еще и в зависимости от результата сравнения - JBE. А вот как выглядит весь код: begin {Устанавливаем графический режим монитора 13h, 320x200, 256 цветов} asm mov ax,0013h int 10h end; asm {Кусок рисования} mov ax,0A000h mov es,ax mov bx,0 @Repeat: mov byte ptr es:[bx],14 add bx,1 cmp bx,319 jbe @Repeat {Кусок рисования - Закончен} end; {Ожидаем нажатия клавиши} asm mov ah,0 int 16h end; {Устанавливаем текстовый режим монитора 03h, 80x25, 16 цветов текста и фона} asm mov ax,0003h int 10h end; end. Примечание ! Обратите внимание, что я выделил комментарием содержательную часть кода, назвав его "Кусок рисования". Далее я не буду приводить весь текст этой небольшой программы, Вам досточно будет заменить только код, названный "Кусок рисования". Остальные команды нам пока непонятны и не будут меняться ближайшее время. Выполните этот код. Убедитесь в наличии желтой полосы вверху экрана. Метка начала цикла у нас называется @Repeat. Почему вначале @ ? Это особенность asm-вставок языка Паскаль. В настоящем ассемблере Вы можете извращаться так, как вам хочется, хотя это ограничение не слишком сильное. Вы могли назвать метку @MY_LABEL. Важно одно: Вы сравнили командой CMP регистр BX с 319, и, если его значение МЕНЬШЕ(BELOW) или(OR) равно(EQUAL) 319, то передаете управление на эту метку. Примечание: Вам должно быть непонятно, ОТКУДА команда JBE знает про результаты выполнения команды сравнения (CMP). Усложним слегка пример. Хочу, чтобы мы нарисовали желтую полосу не по первой сверху строке, а по строке номер 160 ! Думаю, Вам понятно, где начинаются байты, отвечающие этой строке: Номер пикселя по горизонтали/вертикали - номер байта в памяти 0 1 2 160 A0000h+160*320 A0000h+160*320+1 A0000h+160*320+2... А это означает, что начальное смещение в цикле надо задать просто не с нуля, а с 160*320: {Кусок рисования} mov ax,0A000h mov es,ax mov bx,160*320 {Начальное смещение !} @Repeat: mov byte ptr es:[bx],14 add bx,1 cmp bx,160*320+319 {Внимание ! Мы изменили и эту команду !} jbe @Repeat {Кусок рисования - Закончен} Воткните этот кусок вместо прежнего и выполните программу. Убедитесь, что все хоккей - желтая полоса посреди экрана. Важный момент: cmp bx,160*320+319 {Внимание ! Мы изменили и эту команду !} У нас регистр BX уже меняется не от нуля ! И закончим мы рисовать не тогда, когда он станет 320, а когда 160*320+320 ! А теперь еще навороченне !!! Мы можем задавать эффективный адрес, варьируя две компоненты: сегмент и смещение. Только что мы сместили полосу на экране, меняя смещение. Это было естественно, поскольку мы занесли в регистр es такое число, что процессор, умножая его на 16, как раз втыкался в начало видеобуфера: es * 16 = 0A000h * 16 = 0A0000h ! И нам было наглядно задавть смещение от нуля(словно индексация в массиве). Но мы попробуем устроить себе трабл и использовать другое (не 0A000h) значение, заносимое в сегментный регистр es, чтобы нарисовать ту же желтую линию в 160 строке. Нам надо задавть в командах такие вот адреса: Номер пикселя по горизонтали/вертикали - номер байта в памяти 0 1 2 160 A0000h+160*320 A0000h+160*320+1 A0000h+160*320+2... A0000h бралось ранее из es. Смещения - 160*320+0,1,2.. - из bx. А можно ли задать так значение es, чтобы смещение, к примеру, начиналось с 0 ? Вот так: 0 1 2 160 X+0h X+1 X+2... - ? Здесь X - это неизвестное. Оно должно быть получено процессором так: X = es*16 А ячейки памяти должны иметь одинаковые адреса: X+0h = A0000h+160*320. Решая это несложное уравнение, найдем, что X = AC800h = 706560. Значит, es = AC800h / 16 = AC80h ! И измененный код готов: {Кусок рисования} mov ax,0AC80h mov es,ax mov bx,0 {Начальное смещение ! - опять нуль !} @Repeat: mov byte ptr es:[bx],14 add bx,1 cmp bx,319 {Внимание ! Мы изменили и эту команду ! - вернули !} jbe @Repeat {Кусок рисования - Закончен} Заделаем этот пример понагляднее ! Сначала нарисуем желтую полосу в строке 160 "обычным" способом - занося перед циклом в регистр es число 0A000h, а потом нарисуем поверх желтой полосы фиолетовую, но уже занося в es значение 0AC80h ! Вот кодец: {Кусок рисования} mov ax,0A000h mov es,ax mov bx,160*320 {Начальное смещение !} @RepeatYellow: mov byte ptr es:[bx],14 add bx,1 cmp bx,160*320+319 jbe @RepeatYellow {Остановим программу известным нам способом} mov ah,0 int 16h {Рисуем, но уже другим способом !} mov ax,0AC80h mov es,ax mov bx,0 {Начальное смещение ! - опять нуль !} @RepeatMagneta: mov byte ptr es:[bx],13 {Цвет не желтый !} add bx,1 cmp bx,319 jbe @RepeatMagneta {Кусок рисования - Закончен} Проверьте этот код ! Ну вот. А теперь я хочу, чтобы Вы выполнили два небольших заданьица: 1) Заполнить ВЕСЬ экран каким-нибудь цветом. Желательно - красным. 2) Нарисовать горизонтальную полосу зеленого цвета в 64 строке экрана: - занеся в регистр es адрес начала видеобуфера; - занеся в регистр es такое значение, чтобы рисовалась та же полоса в 64 строке экрана, Но вот смещение Вы бы задавали с нуля ! Не возбраняется, а приветствуется появление Ваших решений до выкладки Урока 4, где они будут приведены ! Будет неплохо поглядеть на Ваш код и сделать обсуждам ! Урок 3 закончен. Да пребудет с Вами Великая Сила ! -------------------- I don't like the drugs (but the drugs like me). M.Manson. |
|||
|
||||
Melancholy |
|
|||
Новичок Профиль Группа: Участник Сообщений: 43 Регистрация: 1.4.2002 Репутация: нет Всего: нет |
прога заполняет весь экран красным цветом.
begin {Устанавливаем графический режим монитора 13h, 320x200, 256 цветов} asm mov ax, 00013h int 010h end; asm {Кусок рисования} mov ax, 0A000h mov es, ax xor di, di {обнуляем регистр di} mov al, 004h mov cx, 64000 {счетчик = 64000 = 320 * 200} rep stosb {выполняем 64000 раз команду stosb} {stosb - помещает значение регистра al в ячейку памяти es:di} {Кусок рисования - Закончен} end; {Ожидаем нажатия клавиши} asm mov ah,0 int 16h end; {Устанавливаем текстовый режим монитора 03h, 80x25, 16 цветов текста и фона} asm mov ax,0003h int 10h end; end. а как тебе такой код? |
|||
|
||||
Chingachguk |
|
|||
Эксперт Профиль Группа: Участник Клуба Сообщений: 1232 Регистрация: 25.3.2002 Где: Москва Репутация: 11 Всего: 18 |
Неплохо ! ж) Видимо, ты знаешь ассемблер на каком-то уровне ! Всего одна ошибка: пропустил команду "cld" Но код почти на 100% работает ! Правда, в уроке подразумевалось более "незамысловатое" решение. А как насчет второго задания ? -------------------- I don't like the drugs (but the drugs like me). M.Manson. |
|||
|
||||
Melancholy |
|
|||
Новичок Профиль Группа: Участник Сообщений: 43 Регистрация: 1.4.2002 Репутация: нет Всего: нет |
Вариант 1
begin {Устанавливаем графический режим монитора 13h, 320x200, 256 цветов} asm mov ax, 00013h int 010h end; asm {Кусок рисования} mov ax, 0A000h mov es, ax mov di, 320*64 mov al, 004h mov cx, 320 cld {между прочим вероятность, что флажек CF установлен очень мола!!!} rep stosb {выполняем 64000 раз команду stosb} {Кусок рисования - Закончен} end; {Ожидаем нажатия клавиши} asm mov ah,0 int 16h end; {Устанавливаем текстовый режим монитора 03h, 80x25, 16 цветов текста и фона} asm mov ax,0003h int 10h end; end. Вариант 2 begin {Устанавливаем графический режим монитора 13h, 320x200, 256 цветов} asm mov ax, 00013h int 010h end; asm {Кусок рисования} mov ax, 0A000h + 20*64 mov es, ax xor di, di mov al, 004h mov cx, 320 cld rep stosb {выполняем 64000 раз команду stosb} {Кусок рисования - Закончен} end; {Ожидаем нажатия клавиши} asm mov ah,0 int 16h end; {Устанавливаем текстовый режим монитора 03h, 80x25, 16 цветов текста и фона} asm mov ax,0003h int 10h end; end. P.S. Что ты имеешь введу "почти на 100% работает"? |
|||
|
||||
Правила форума "Asm для начинающих" | |
|
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, MAKCim. |
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | Asm для начинающих | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |