![]() |
Страницы: (17) Все « Первая ... 3 4 [5] 6 7 ... Последняя »
( Перейти к первому непрочитанному сообщению ) |
![]() ![]() ![]() |
|
Chingachguk |
|
|||
Эксперт ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1232 Регистрация: 25.3.2002 Где: Москва Репутация: 11 Всего: 18 |
-------------------- I don't like the drugs (but the drugs like me). M.Manson. |
|||
|
||||
Uchenik |
|
|||
Unregistered |
Chingochguk
![]() задания и смиренно жду 4-й урок. |
|||
|
||||
Chingachguk |
|
|||
Эксперт ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1232 Регистрация: 25.3.2002 Где: Москва Репутация: 11 Всего: 18 |
Хм. Я давно думал что-то написать в продолжение, вот только не решил, что именно. Смысл в том, что начальная теория, я считаю, изложена и далее должна идти практика. Практика позволит закрепить знания и улучшить технику. Вопрос в том, какая именно практика: порты ввода-вывода, работа с прерываниями, передача и получение параметров в/из ассемблерного кода из/в язык Паскаль (или Си) или вообще что-то типа написания кода загрузчика (MBR-сектор).
Вообщем, пишите Ваши пожелания - что именно Вы бы хотели узнать о Машине - и, возможно, мы сделаем это на языке ассемблера ;) -------------------- I don't like the drugs (but the drugs like me). M.Manson. |
|||
|
||||
vanya |
|
|||
Unregistered |
Помогите зарегистрированному Ламмеру с прогой Ассемблер!
|
|||
|
||||
Shuricksoft |
|
|||
Бывалый ![]() Профиль Группа: Участник Сообщений: 177 Регистрация: 27.3.2002 Где: Odessa, Ukraine Репутация: нет Всего: нет |
Chingachguk, вот я бы хотел изучить работу с внешними устройствами - объяснишь заодно и порты, и прерывания =) А потом бы хотел загрузчик. Вот тебе пожелания - надеюсь, ты их осуществишь в ближайшем времени, за что я тебе заранее благодарен
![]() |
|||
|
||||
Chingachguk |
|
|||
Эксперт ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1232 Регистрация: 25.3.2002 Где: Москва Репутация: 11 Всего: 18 |
О'кей ;)
Приянто к сведению ;) -------------------- I don't like the drugs (but the drugs like me). M.Manson. |
|||
|
||||
Baa |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 2639 Регистрация: 12.4.2002 Где: Москва Репутация: нет Всего: 12 |
Shuricksoft, на wasm.ru сейчас идет серия статей про загрузчики...
-------------------- "Duty is everything; the greatest of joys, the deepest of sorrows" Aribeth de Tylmarande |
|||
|
||||
Shuricksoft |
|
|||
Бывалый ![]() Профиль Группа: Участник Сообщений: 177 Регистрация: 27.3.2002 Где: Odessa, Ukraine Репутация: нет Всего: нет |
Baa, сенкс! Завтра гляну... Но всё равно Chingachguk forever :-)
|
|||
|
||||
Chingachguk |
|
||||||
Эксперт ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1232 Регистрация: 25.3.2002 Где: Москва Репутация: 11 Всего: 18 |
Урок 4: прерывания.
Итак, в этом уроке мы попробуем "почувствовать" прерывания. Что такое прерывания ? Допустим, вы решаете идете по лесу и собираете грибы. Ваш мозг, вероятно, думает о том, где же спрятались эти белые, лисички и т.п. Вдруг вас кусает комар. Практически не задумываясь вы бьете рукой по месту укуса и думаете себе дальше о грибах. Проанализируем ситуацию с точки зрения посторения программного кода. Иногда это называют странными словами "построить блок-схему", но мы ограничимся обывательским методом описания: Основная процедура поиска:
Процедура обработки события "укусил комар":
Таким образом, мы написали костяк основной процедуры поиска грибов и вспомогательную подпрограмму реакции на укус комара. Как же нам связать их в одну целую программу ? Ведь в любой момент выполнения основной программы может быть нужно выполнить подпрограмму обработки кусания и безболезненно вернуться к выполнению основной. Здесь нам на помощь приходят так назывемые "прерывания". Смысл в том, что будет использован некий диспетчер, который будет по необходимости вызывать ту или иную подпрограмму. В нижеизложенном примере решается следующая задача: основная программа рисует квадрат в некотором месте с некоего начального размера до максимального, но специальная подпрограмма, получающая управление по тикам таймера принудительно изменяет случайным образом месторасположение квадрата на экране и его цвет, тем самым заставляя рисовать квадрат основной код на новом месте:
Задания: 1. В приведенном коде попробовать отключить принудительное изменение цвета или координаты начала квадрата; 2. Попробовать переписать код, рисующий квадраты, на ассемблере; 3. (Самое сложное !) изменить частоту принудительной смены параметров отрисовки с большей на меньшую (например, 1 раз в секунду). -------------------- I don't like the drugs (but the drugs like me). M.Manson. |
||||||
|
|||||||
Shuricksoft as a guest |
|
|||
Unregistered |
Hi! =)
Наконец-то у меня появилось свободное время и я взялся за урок! =) Спишу доложить результаты =) Сделал задания 1 и 3 без проблем, за второе пока не брался, завтра займусь. 1. Отключить принудительное изменение координаты начала можно, убрав строку mov word ptr es:MyScreenCenter,ax Для цвета - строка mov byte ptr es:MyScreenColor,al 3. Привожу изменённый кусок кода:
Теперь вопросы. Что означает новый оператор lds и как используется? Как используется оператор mul? Почему MyRandVal умножается именно на 16807? Пока что всё... P. S. Теперь буду стараться значительно чаще заходить сюда и учить уроки ассемблера =) |
|||
|
||||
Shuricksoft as a guest |
|
|||
Unregistered |
О, я даже чуть оптимизировал третье задание с утра =)
Как я понимаю, с регистрами работать намного быстрей и приятней, чем с переменными, поэтому...
Сейчас займусь вторым заданием =) А вопросы остаются прежними... |
|||
|
||||
Chingachguk |
|
||||
Эксперт ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1232 Регистрация: 25.3.2002 Где: Москва Репутация: 11 Всего: 18 |
Хм... Первый вариант (теоретически) был верный (я насчет 1 раз в секунду). Во втором случае никто не гарантирует сохранение регистра CX на пути от приложения (основной код, рисующий прямоугольники) через обработчик прерывания BIOS к нашему обработчику прерывания и обратно. Кроме того, "не хорошо" менять в обработчике прерывания регистры "как угодно", если только это не предусмотрено специально (например, для передачи параметров и т.п.) Поясню на примере, почему это может быть неверно. Допустим, в машине работает только два куска кода:
; Прерывание MyHandler: ; ... ; Основной код MainCode: ; ... Прерывание получает управление асинхронно, т.е. случайно во времени относительно выполнения MainCode - например, 20 раз в секунду. Если теперь написать: ; Прерывание MyHandler: cmp cl,18 jb @@Skip ; ... @@Skip: inc cl ; Основной код MainCode: mov cl,0 @@MainCycle: ; We dont use CX here ! jmp @@MainCycle То вроде все OK - и только прерывание меняет регистр внутри себя. На самом деле первым получает управление BIOS и картинка усложняется: Приложение -> (прерывание)BIOS-код -> Твое прерывание-> Обратно в BIOS->Обратно в Приложение. Например: ; Прерывание MyHandler: cmp cl,18 jb @@Skip ; ... @@Skip: inc cl ; BIOS StartBIosInt8Handler: ; ... ; А вдруг BIOS тут использует CX ? call MyHandler ; А вдруг BIOS тут использует CX ? iret ; Основной код MainCode: mov cl,0 @@MainCycle: ; We dont use CX here ! jmp @@MainCycle Но это не главное. Ведь вряд ли в реальном коде, который использует прерывания, можно обойтись без использования CX. Например, обработчик от таймера переодически опрашивает устройство, а основной код - это интерфес с кнопками. Поэтому гораздо проще сосредоточить внимание на небольшом коде обработчика нежели везде следить за тем, чтобы не юзать CX. А если ты используешь стандартные библиотеки Паскаля (СИ, etc ?). Ну а первый вариант, как я говорил, верный.
lds - это более краткий способ написать пару команд: mov SEG_REGISTER,memory+2 mov USAL_REGISTER,memory Например, такой случай: в памяти, доступной через es:[bx+20] лежат два слова: смещение и сегментный адрес, которые надо занести в регистры ds:dx: mov dx,word ptr es:[bx+20] mov ds,word ptr es:[bx+20+2] С помощью lds это сделать проще: lds dx,dword ptr es:[bx+20]. Существуют также команды les (es), lss (ss). Однако работа с сегментными регистрами уже остается только дос-приложениям или коду уровня ядра. Win32-код очень редко использует их. LDS является сокращением от ~"load pointer using DS".
Оператор mul - это команда целочисленного умножения. Всегда умножается регистр AX или AL (в 32 битном коде - eax) на другой регистр или память: mov ax,10 mov bx,10 mul bx ; В результате в паре dx:ax содержится unsigned long 100 mov al,10 mov bl,10 mul bl ; В результате в ax содержится unsigned short 100 MyVar db 10 ; ... mov al,10 mul byte ptr MyVar ; В результате в ax содержится unsigned short 100 Существуют также команды знакового умножения imul. Почему умножение на 16807 ? Это довольно-таки от балды взятое число из генератора псевдослучайных чисел. Общий вид конгруэнтного генератора: static unsigned long RandVal; void RandSeed(void) { RandVal=time(NULL); } unsigned long Rand(void) { RandVal=RandVal*A+B; return(RandVal); } Таким образом, следующее число генератора на i-м шаге равно: RandVal[i+1]=(RandVal[i]*A+B) mod 2^32 (зависит от размерности ulong). В моем случае я не делал чего-то особо сложного, а выбрал: A=16807; B=0; Размерность - 2^16 (Word). -------------------- I don't like the drugs (but the drugs like me). M.Manson. |
||||
|
|||||
Shuricksoft as a guest |
|
|||
Unregistered |
Chingachguk, я тоже засомневался по поводу CX, но проверил - работает =) А потом подумал: ведь основной код данной программы не использует этот регистр. БИОС его использовать также не может. Почему? А потому что, когда мы юзаем CX в основном коде, БИОС точно так же получает управление, но ничего страшного не происходит, следовательно CX БИОСу не нужен. При использовании стандартных библиотек Паскаля или С могут быть ошибки - тут я с тобой полностью согласен. Но в нашем случае это не принципиально =)
По поводу ответов на мои вопросы всё понятно, спасибо. Теперь переделка кода рисования на ассемблер:
Но! Квадраты рисуются очень медленно, а на первых порах ещё и цвет фона меняется. В чём ошибка? И ещё: как записать if MyScreenBarSize>=MaxBarSize then MyScreenBarSize:=1; на ассемблере? А для организации repeat until keypressed надо ставить свой обработчик на прерывание клавы? И нельзя ли значения переменным присваивать напрямую, а не через регистры? |
|||
|
||||
Chingachguk |
|
|||
Эксперт ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1232 Регистрация: 25.3.2002 Где: Москва Репутация: 11 Всего: 18 |
О, это тонкая ошибка ! Попробуй сам догадаться, в чем дело (верный код):
По поводу быстродействия - попробуй также решить сам задачу оптимизации тела этих двух циклов. Подсказка: если что-то можно сделать вне цикла, то это следует вынести за цикл. Именно не оптимизировать, заменив переменные IndX и т.п. на регистры. -------------------- I don't like the drugs (but the drugs like me). M.Manson. |
|||
|
||||
Shuricksoft as a guest |
|
|||
Unregistered |
По-моему, единственная разница при выполнении новой версии кода - это то, что при окончании цкла значение IndX или У = MyScreenBarSize + 1 (у меня - просто MyScreenBarSize). Цикл же выполняется для одинаковых значений в обоих случаях. Но ведь Паскалевское for IndX := 1 to MyScreenBarSize в конце тоже выдаст MyScreenBarSizr (без 1). Я что-то совсем запутался :-/
По поводу оптимизации, пользуясь твоей подсказкой, вынес строки mov ax,0A000h mov es,ax непосредственно перед началом циклов. Больше ничего сделать не смог. |
|||
|
||||
![]() ![]() ![]() |
Правила форума "Asm для начинающих" | |
|
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, MAKCim. |
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | Asm для начинающих | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |