← Ноябрь 2000 → | ||||||
1
|
2
|
3
|
4
|
5
|
||
---|---|---|---|---|---|---|
6
|
7
|
8
|
9
|
10
|
11
|
12
|
14
|
15
|
16
|
17
|
18
|
19
|
|
20
|
22
|
23
|
24
|
25
|
26
|
|
27
|
28
|
29
|
30
|
За последние 60 дней ни разу не выходила
Сайт рассылки:
http://rusfaq.ru
Открыта:
28-06-2000
Статистика
0 за неделю
Ассемблер? Это просто! Учимся программировать Выпуск N 014
Какой чудесный день! Какой крутой мой "Пень"! Какой веселый я: Рассылочка пришла! Чего у нас сегодня-то?
Пожалуйста, возьмите предыдущие выпуски по следующему адресу: http://www.oleg77.newmail.ru (здесь также можно найти все необходимое программное обеспечение для работы с Ассемблером). Если у Вас нет доступа в Сеть, то напишите мне письмо по адресу: assembler@beep.ru?Subject=Issues Если в поле "Тема" Вы укажите слово Issues, то ВСЕ предыдущие выпуски будут высланы Вам автоматически; это существенно ускорит ответ. Обратите внимание, что у меня изменился электронный адрес, а также адрес сайта, что не было исправлено в предыдущих выпусках! Ох, друзья мои! Ну и болел же я! Целую неделю. К сожалению, так и не смог выпустить этот номер рассылки вовремя. В связи с этим прошу прощения за такую длинную задержку. Хотелось бы и вас предупредить: будьте осторожны! Не болейте! Дорогие мои подписчики! Я печатаю рассылку для того, чтобы вы научились писать программы на Ассемблере. Более того, я очень хочу привить у вас любовь к самому языку и показать то, что он не такой уж сложный. Я очень рад тому, что многие испольуют информацию с рассылки для написания контрольных и/или лабораторных работ. Я просто счастлив, что смог кому-то помочь! Однако, я был бы очень разочарован, узнав, что информация из рассылки "Ассемблер? Это просто! Учимся программировать" используется кем-то в коммерческих целях. Прошу вас: уважайте, пожалуйста, чужой труд! Если у вас есть предложение по использованию информации в рассылке не только для собственного, частного использования, но и в коммерческих целях (сюда НЕ входит написание собственных рефератов, контрольных и лабораторных работ и т.п.), то, будьте так добры: напишите мне ваше предложение! Мы найдем общий язык! В противном случае, мне придется поступать по всей строгости Закона РФ "Об авторских и смежных правах". ____________________ Ко мне пришло много писем с просьбой включить e-mail в базу данных с тем, чтобы автоматически высылать вам файлы-приложения к рассылке (sshell.asm, virus.asm, resid.asm). Я отправляю их порциями по 10-20 адресам. Верю, что все подписчики порядочные и солидные люди. Однако, если кто-либо получит некоторое подобие спама, используя адреса, перечисленные в поле "Кому:", сообщите мне об этом. Будем таких искать и безбожно бить ногами... ___________________ Почему мы пишем только *.com файлы? Да потому, что модель памяти в Windows очень напоминает модель памяти *.com-файлов, которые мы сейчас рассматриваем. Конечно, мы напишем несколько примеров *.exe-файлов, но это будет попозже. К слову. Модель памяти в *.com-файлах называется TINY (крошечная). В Windows - FLAT (плоская или как это?). ____________________ Хочу спросить у образованных людей: есть ли в русском языке слово "запомненный"? Если нет, то каким словом его можно заменить? Пример: "Достаем со стека запомненный адрес строки". Спасибо! ____________________ Совсем недавно я поместил на сайт свой небольшой фотоальбом, в котором можно посмотреть фотографии моей жены, сына, брата, сестры, отца, матери, а также меня лично. Если Вам интересно, то можете заглянуть в свободное время... Итак, время пришло! Некоторые уже ознакомились с условиями на сайте, но я все же рекомендую прочитать то, что находится в данном разделе рассылки, причем всем подписчикам. Не все имеют прямой и постоянный выход в Сеть. В связи с этим я постараюсь вкратце объяснить суть нашего так сказать эксперимента. Почему я решил сделать это? Ко мне приходит много писем с различными вопросами (как по Ассемблеру, так и по другим темам; например, по работе с DOS). Я, как уже писал, не успеваю отвечать на все ваши письма. Поэтому я решил провести небольшой эксперимент: создать т.н. "Клуб экспертов". Что из себя представляет этот (как его?) "Клуб экспертов"? В него может войти любой человек, который решит принять на себя ответственное и непростое задание и попробоваться в роли "учителя", стать т.н. экспертом. Или, проще говоря, отвечать компетентно на вопросы подписчиков. Например:
Зато у Сергея есть время, определенные знания и желание отвечать на вопросы, помогать другим освоить Ассемблер, но нет возможности. Более того, Сергей знает, что при объяснении темы или при ответе на вопрос сам чего-то да начинает понимать. Т.е. будет учиться сам, обучая других. Я хочу предоставить эту возможность Сергею и всем остальным, кто имеет то же желание. Каков принцип работы клуба? Например, у меня зарегистрировалось 5 специалистов-экспертов, которые изъявили желание отвечать на вопросы связанные с DOS. Вася (который не может разобраться с DOS) высылает мне письмо с вопросом, которое автоматически направляется всем пятерым экспертам. Эксперты, в свою очередь, отвечают на вопрос и отправляют его напрямую Васе. Т.о. Вася получит 5 писем с ответами на свой вопрос. Из одного письма он почерпнет одно, из другого - второе и т.д. При этом эксперт направляет мне копию данного письма. Нет, не для того, чтобы я проверял, а для того, чтобы я мог создавать потихоньку базу данных вопросов/ответов, которую потом выложу на сайт. При этом, естественно, письмо будет сохранено в первозданном виде, причем имя и e-mail эксперта остается (если он этого захочет). Что я могу предложить экспертам? Вася, получивший 5 писем с ответами направляет мне оценки всем пяти экспертам по пятибалльной шкале (неужели Васе будет это сложно сделать?). Т.е. Валик ответил на "отлично", а Толик на "троечку" еле тянет. Я периодически опубликовываю в рассылке имена экспертов и количество набранных ими баллов. Тройка лидеров получает возможность:
Эксперт, занявший первое место, может получить, помимо вышеперечисленного, еще и денежку за труды. Много не обещаю, т.к. собираюсь платить со своего кармана, но на пивко хватит. Почему я написал "может"? Потому что какое-то время (пока система не заработает в определенном ритме, если она вообще заработает!) денежки выплачиваться не будут. Зато потом можно будет заработать не только на пивко, но еще и на воблочку. А там, глядишь, и до икорки дойдет... По крайней мере, я очень на это надеюсь... Но не все так просто. Все эксперты должны соблюдать определенные правила, которые будут высланы им в скором времени. Количество экспертов ограничивается пока 10 человеками на одну тему. Что требуется от подписчиков, задающих вопросы? Прежде всего - порядочность и внимательность. А именно:
Все вышеперчисленное - самое главное! Для этого я и хочу сперва пропускать письма через свой ящик. _______ Ниже приведена перечень тем для вопросов, который будет теперь присутствовать во всех выпусках (может, чего-нибудь другое придумаю, чтобы не нагружать выпуски). С левой стороны указана экспертная группа, а справа, в скобках типичный вопрос к данным экспертам, после этого указан адрес с меткой в поле "Тема", откуда нужно будет отправлять вопрос:
Пожалуйста, проверяйте, чтобы в поле "Тема" Вашего вопроса была соответствующая строка, которая идет после "?Subject=" !!! Вопросы, которые вы присылали мне и не получили ответ, пожалуйста, пререшлите соответствующим экспертам. Спасибо. Сегодня у нас довольно-таки нудный и неинтересный выпуск. Но то, что мы будем рассматривать в нем, очень важно! Вам придется вспомнить основы математики и немного "пошевелить мозгами". Да-да, друзья мои! А как вы хотели выучить Ассемблер без элементарных знаний математики? Я подчеркиваю: элементарных. Вам придется хорошо поработать сегодня! Хотя, большую часть работы я для вас сделал, а именно: продумал алгоритм вывода на экран любого окна (или рамки) в центр экрана. Вам осталось только внимательно с ним ознакомиться и разобраться. Полная просьба: внимательно ознакомьтесь с данным выпуском и прилагаемым к нему файлом Sshell14.rar! Файл-приложение можно взять здесь: http://www.oleg77.newmail.ru/Assembler/Programs/Lessons/Sshell14.rar Если у вас нет выхода в Сеть, то напишите мне письмо с просьбой выслать. Я также включу ваш адрес в базу данных. Затем, перед выходом очередной рассылки, вы получите этот файл по почте. Давайте договоримся о некоторых определениях. Т.к. программа у нас будет большая, то для облегчения читаемости и поиска необходимой процедуры, я буду указывать в скобках процедуру и файл, где нужно искать то, о чем я напишу в рассылке. Например, "...Затем мы удаляем файл (Delete_file, FILES.ASM)..." Здесь: Delete_file - процедура, которая удаляет файл, а FILES.ASM - файл, где нужно ее искать. Ну, понеслась... Сразу заглядываем в файл MAIN.ASM. Перво-наперво, что нам нужно сделать, так это спрятать курсор (Hide_cursor, DISPLAY.ASM). Прежде, чем это сделать, нужно запомнить его текущую позицию. Это позволяет сделать функция 3 прерывания 10h:
Как видите, BH должен указывать на видеостраницу, с которой нужно сосчитать позицию курсора. Как уже вам известно, видеокарта имеет достаточно памяти для размещения 8 видеостраниц. Каждая видеостраница имеет свой курсор. Но мы-то будем отображать все на нулевой странице, следовательно, мы должны в BH загрузить 0. На выходе DX будет содержать текущую позицию курсора: DH - строку, а DL - колонку. Причем, отсчет идет с нуля. После того, как мы получили текущую позицию курсора, можно его прятать. Самый распространенный метод - установка курсора за границу экрана. В нашем случае - установка на 25 строку. Режим-то у нас будет 3 (25 строк, 80 колонок). Т.к. отсчет идет с нуля, то последняя позиция курсора (самая нижняя строка) - 24. Следовательно, установив курсор на 25 строку (19h), мы его просто "прячем"! Установить курсор на нужную позицию на экране позволяет сделать функция 2 прерывания 10h:
После того, как мы спрятали курсор, можем переходить к сохранению текущего содержания видеостраницы 0. Как вы знаете, все уважающие себя оболочки сохраняют и, при необходимости, показывают пользователю то, что изображено на экране. Например, Norton Commander или DOS-Navigator, которые отображают пользовательский экран при нажатии на клавиши <Ctrl+O>. Как ее сохранить? Помните, я говорил о том, что у видеокарты есть достаточно памяти для размещения 8 видеостраниц? Почему бы нам не скопировать содержимое пользовательской, нулевой страницы в первую? А что тут такого? Вот мы это и делаем (Save_mainscr, DISPLAY.ASM). Здесь мы встречаем новые операторы: PUSHA и POPA (POPA значит POP All - вытолкнуть все (а не то самое...), а PUSHA - PUSH All - втолкнуть все). Т.е. этот оператор толкает в стек регистры в следующем порядке: AX, CX, DX, BX, SP, BP, SI и DI и, соответственно, оператор POPA выталкивает их из стека в обратном порядке, т.е.: DI, SI, BP, SP, BX, DX, CX и AX. Данные операторы используются только 286+ процессором. Когда пишут, например, что такой-то оператор используется в 386+ процессоре, то это значит, что данный оператор будет работать на процессорах 80386, 80486, Pentium и т.д., но никак не на 8086 (PC/XT) и 80286 (PC/AT). В нашем случае команды PUSHA и POPA будут работать на 80286 и последующих (более современных) процессорах. Для этого в самом начале файла SSHELL.ASM мы указываем т.н. дерективу .286, что говорит ассемблеру (MASM, TASM) о том, что в данной программе могут встречаться команды (инструкции) не только 8086 процессора, но и 80286. "Почему же мы раньше ничего подобного не писали?" - спросит внимательный читатель. "Если ничего подобного не указывать, то ассемблер (MASM, TASM) считает, что в программе используются только инструкции 8086 процессора, что мы до сих пор и делали..." - ответит ваш покорный слуга. Безусловно, команды PUSHA и POPA удобны в тех случаях, когда нам нужно сохранить в стеке более одного регистра. Они уменьшают размер программы. Обратите также внимание, как мы заносим в сегментный регистр число: push 0B800h pop es Это получается на 1 байт короче, чем если бы мы делали так: mov ax,0B800h mov es,ax Более того, мы не трогаем регистр AX, что в некоторых случаях бывает полезно. Команда вида PUSH 1234h работает также на процессорах 80286+ (если быть точным, то она работает на процессоре 80186+, но т.к. эти процессоры не получили большого распространения в связи с тем, что через несколько месяцев после выпуска 80186 появились 80286, то о них (о 80186) вообще мало кто знает). Все остальное в данной процедуре (Save_mainscr, DISPLAY.ASM) должно быть понятно... Точно как и в процедуре восстановления экрана (Restore_mainscr, DISPLAY.ASM)... _______________ Теперь самое нудное (на мой взгляд). Курсор спрятали, экран пользовательский сохранили. Тепрь можно и окно (рамку) рисовать... Будем это делать не прибегая ни к каким прерываниям, т.к.они работают очень медленно. Воспользуемся выводом символов на экран путем прямого отображения в видеобуфер. С данным методом мы уже сталкивались, когда пытались выводить на экран "рожицу". Теперь рассмотрим его более подробно. Метод прямого отображения символов в видеобуфер - вывод символов на экран, путем записи их напрямую в сегмент видеобуфера (в память видеокарты), минуя сервис прерываний. Стоит отметить, что это самый быстрый способ вывода символов на экран. Быстрее уже не существует. Здесь все зависит от профессионализма программиста и - как следствие - алгоритма вывода, скорости его выполнения. Рассмотрим вкратце модели мониторов, многие из которых уже уши в прошлое, и только старые и добрые игрушки периодически напоминают об их существовании. Вот ряд: MDA (Monochrome Display Adapter), Hercules, CGA (Color Graphic Adapter), EGA (Enchanced Graphic Adapter), VGA (Video Graphic Array), MCGA (Multi-Color Graphic Adapter - подобие VGA), sVGA (Super Video Graphic Array - то, что многие в настоящий момент используют в работе). Так вот, при попытке вывода символа в мониторе CGA и подобных ему возникает т.н. "снег". Эта ошибка (недоработка?) была исправлена только в EGA. "Снега" не возникало, если символы выводились при помощи прерываний 10h или 21h. Однако, эти прерывания использовали процедуру, которая проверяла состояние луча монитора, в связи с чем скорость вывода символов существенно замедлялась. Не знаю, есть ли в настоящих ПЗУшках и в прерывании 21h подобная процедура или нет. Главное - при выводе символов через прерывания скорость резко снижается. Полагая, что никто из вас не использует сейчас CGA монитор, будем выводить символы прямым отображением в видеобуфер. Повторю еще раз: это очень быстро даже на 8086 процессорах. Очистка экрана в PC/XT происходит мгновенно. И уж тем более на 80286+... Для процедуры (а может и не только для нее) заведем две переменные: Height_X и Width_Y. Пока временно. В дальнейшем научимся передавать данные в стеке. Но это будет позже, а сейчас переменная Height_X содержит высоту рамки, а Width_Y - ширину. Num_attr - цвет рамки (Main_proc, MAIN.ASM). Можно вызывать процедуру Draw_frame, которая находится в файле DISPLAY.ASM. Вот сейчас и рассмотрим самое главное. Итак, процедура Draw_frame. Перед вызовом данной процедуры необходимо занести некоторые числа в соответствующие переменные (main.asm), а именно: Height_X - содержит высоту нашей рамки; Width_Y - содержит ширину нашей рамки; Num_attr - содержит атрибуты выводимой рамки. Пока все. Дальше пойдем - больше будет... Итак, занесли. Вызываем процедуру Draw_frame (Display.asm). Теперь внимание! Нужно произвести некоторые расчеты перед тем, как вывести рамку не "абы куда", а именно в самый центр экрана. Нам нужно разделить высоту рамки на 2 и вычесть из полученного числа середину высоты. Вот так: (1) mov ax,Height_X (2) shr al,1 (3) mov dh,11 (4) sub dh,al В строке (1) заносим в AX высоту рамки, которую указали перед вызовом процедуры. Затем, в строке (2), оператор SHR сдвигает все биты в регистре AL на 1 вправо. Что получается? Вот пример: mov ax,16 --- AX = 10000b, т.е. 16 shr ax,1 --- AX = 1000b, т.е. 8 shr ax,1 --- AX = 100b, т.е. 4 shr ax,1 --- AX = 10b, т.е. 2 shr ax,1 --- AX = 1b, т.е. 1 Т.о. сдвиг битов вправо на единицу делит число на 2. На двойку - в четыре раза и т.д. Это быстрее, если бы мы пользовались оператором DIV (который, кстати, мы еще не изучили) - деление. В строке (3) мы заносим в DH середину (или почти середину) экрана (по горизонтали), т.е. 11. И вычитаем из 11 полученный результат. Например, мы выводим рамку высотой в 5 строк. Вот, что получим: AX=10 AX=AX/2=5 AX=11-5=6 Т.о. вывод начнем со строки 6. Все тоже самое мы делаем с колонками (вертикально). Посмотрите в прилагаемом примере... В принципе, пока особо не заостряйте внимание на этом: со временем придет опыт и более точное понимание. Как только мы вычислили координаты для вывода рамки в центре экрана, мы переводим высоту/ширину в линейный адрес. Что такое линейный адрес и зачем нужно переводить в него? Как вы уже знаете, то, что находится на экране, расположено по адресу от 0B800:0000 до 0B800:1000h (если нулевая страница). Видеокарта не знает, что такое колонка и строка. Для нее все данные расположены в линейном массиве, т.е. от 0 до 1000h. Т.к. один символ занимает 2 байта (символ и атрибут), то одна строка 3 режима занимает 160 байт (80 строк * 2 = 160). Для того, чтобы вывести символ в первую строку (т.е. во вторую, т.к. отсчет с нуля), нам нужно выводить его по адресу 161, смещения 0B800h. Следовательно, если мы указываем сторку/столбец, то нам необходимо перевести эти числа в линейный массив, "понятный" видеокарте. Вот пример (разбираем внимательно!): mov dh,0 ;DH обычно указывает на строку mov dl,15 ;а DL - на столбец (это мы и будем делать во всех наших процедурах) ;т.о. мы выводить будем в нулевой строке (т.е. самой верхней на экране), 15 столбце. Вот переводим два числа в линейный массив (переведем в одно число - смещение): Linear = DL*2 Умножаем на два строку, т.к. один символ на экране занимает два байта: символ+его атрибут Linear = Linear + DH*160 Теперь переменная Linear равна 30. Вот он, линейный адрес: 0B800:001Eh (1Eh = 30)! Еще пример: mov dh,8 ;строка 8 mov dl,56 ;столбец 56 Linear = DL*2 теперь Linear = 112 Linear = Linear + DH*160 Теперь Linear = 1392 или 570h И последний пример. Произведем вычисления для последнего символа на экране (нижний правый угол): Linear = (24 * 160 + 80 * 2) - 2 = 0F9Eh 80 - количество столбцов на экране, которое нужно умножить на 2 (учитывая не только символ, но и его атрибут). 24 - количество строк на экране, начиная от 0. Т.к. в одной строке 80 символов (начиная от 1) * 2 = 160, то, для того, чтобы получить адрес самого последнего (24-ого) ряда, нужно 24*160. Затем все это дело сложить (адрес 24-ой строки плюс адрес последнего символа минус два). Еще раз: (24-ая строка * 160 + 80-ый символ * 2) - 2 или (24 * 160 + 80 * 2) - 2 = 3998 или 0F9Eh Почему "минус два"? Потому, что... А, хотя, подумайте сами... Я и так тут порасписывал... Я лучше расскажу, как это выглядит на практике. Итак, процедура (Get_linear, DISPLAY.ASM) (хотя, многое и так понятно из описаний в файле): shl dl,1 ;умножаем DL на 2 (DL=DL*2)... Просто сдвинем биты на 1 влево (по принципу деления. См. выше). mov al,dh ;в AL - ряд, Что-что? Новый оператор MUL? Ну так рассмотрим сейчас. mov di,ax ;результат умножения в DI Итак, вот таблицы с новыми операторами:
Пример: mov ax,100b shl ax,1 ; Теперь в AX число 1000b --------
Пример: mov ax,100b shr ax,1 ; Теперь в AX число 10b --------
Умножает AL на BL, помещая результат в AX. Пример: mov al,5 mov bl,2 mul bl ; Теперь в AX число 10 Ну вот, собственно, и все. Остальное должно быть понятно из комментариев к программе. Если у Вас есть вопросы, то задавайте их, пожалуйста, экспертам (в редких случаях можно и мне). Удачного Вам программирования! С уважением,
|
http://subscribe.ru/
E-mail: ask@subscribe.ru |
В избранное | ||