Page 66 of 77

Re: Помогите новичку

Posted: Wed Mar 11, 2015 11:32 am
by Gluk
если подробно, то жаль нет уточнения что за языки высокого уровня вы используете, чтобы объяснить. Допустим, это Python:

Code: Select all

def wait_event():
    while True:
        event = mcall(10)
        event -= 1
        if event == 0:
            redraw()
        event -= 1
        if event == 0:
            key()
        if event == 3:
            button_event()
это то, что вы написали. Теперь, посмотрим, что будет если mcall(10) вернёт 3 (то, что нужно вроде):
сперва event уменьшится на единицу, станет равным 2.
2 не равно 0, так что событие не перерисовка, идём дальше
event уменьшится на единицу, станет равным 1.
1 не равно 0, так что событие не кнопка клавиатуры, идём дальше
event сравнивается с тремя.
1 не равно 3, значит кнопку никто не нажимал. Или нажимал?...

Re: Помогите новичку

Posted: Wed Mar 11, 2015 12:53 pm
by gc986
Gluk wrote:если коротко, следует заменить

Code: Select all

cmp   eax,3
на

Code: Select all

dec   eax
Спасибо!
Я хотел закрывать экран по нажатию на кнопку, сейчас закрытие происходит и по кнопке и по крестику. Как определять что событие пришло от конкретного компонента (кнопки на экране), а не от системной кнопки закрытия? Нужно её идентификатор указывать?
С помощью какой инструкции можно поменять текст на надписи?

Re: Помогите новичку

Posted: Wed Mar 11, 2015 1:11 pm
by Gluk
gc986 wrote: Спасибо!
Я хотел закрывать экран по нажатию на кнопку, сейчас закрытие происходит и по кнопке и по крестику. Как определять что событие пришло от конкретного компонента (кнопки на экране), а не от системной кнопки закрытия? Нужно её идентификатор указывать?
С помощью какой инструкции можно поменять текст на надписи?
Всегда пожалуйста!
думаю, в данном случае следует применить системную функцию 17, о которой можно прочитать например вот на этой странице http://wiki.kolibrios.org/wiki/SysFn17/ru . Вызывать её наверное следует в участке кода, который выполняется когда нажата кнопка, то есть, скорее всего, в процедуре button_event. Если непонятно как применить, спрашивайте свободно

Re: Помогите новичку

Posted: Wed Mar 11, 2015 1:41 pm
by gc986
Gluk wrote: Всегда пожалуйста!
думаю, в данном случае следует применить системную функцию 17, о которой можно прочитать например вот на этой странице http://wiki.kolibrios.org/wiki/SysFn17/ru . Вызывать её наверное следует в участке кода, который выполняется когда нажата кнопка, то есть, скорее всего, в процедуре button_event. Если непонятно как применить, спрашивайте свободно
Т.е. необходимо произвести сравнение содержимого регистра eax с 17, если равны, то ничего не делать, иначе производить выход из приложения.

Code: Select all

cmp eax, 17
jne close_program
jmp wait_program
Видимо делаю что-то не то, так как выходит и при нажатии на кнопку и при нажатии на кнопку закрытия окна. Как должно быть правильно?

Re: Помогите новичку

Posted: Wed Mar 11, 2015 2:39 pm
by Gluk
не совсем. Сначала нужно вызвать системную функцию:

Code: Select all

mcall   17
сразу после этого в регистре ah очутится идентификатор кнопки, которая нажата.
идентификатор (упрощённо говоря) это то, что у вас в коде:

Code: Select all

mcall   8, <30,50>, <30,20>, 1, 0xf0f0f0
равно 1. Я не писал под Колибри уже годы, так что не помню какой идентификатор по умолчанию у кнопки-крестика приложения, и быстро найти не удалось, поэтому (для быстрого старта и чтобы точно работало) порекомендую использовать вместо 1 более уникальный идентификатор, например 0xBE. То есть заменить ту строку на:

Code: Select all

mcall   8, <30,50>, <30,20>, 0xBE, 0xf0f0f0
Возвращаясь к нашей button_event: надо будет после вызова 17й функции сравнить ah с 0xBE:

Code: Select all

cmp ah, 0xBE
вместо

Code: Select all

cmp eax, 17
.

Далее, если вы хотите по этой кнопке как раз закрывать окно, то следует применить

Code: Select all

je close_program
вместо

Code: Select all

jne close_program
.

Если я ничего не путаю, у нас получается (не забываем ещё 1 на 0xBE сменить):

Code: Select all

button_event:
   mcall 17
   cmp  ah, 0xBE
   je   close_program
   jmp   wait_event
и программа не будет завершаться по крестику, а только по вашей кнопке

Re: Помогите новичку

Posted: Wed Mar 11, 2015 3:03 pm
by Gluk
gc986 wrote:С помощью какой инструкции можно поменять текст на надписи?
если поменять произвольным образом, то весьма просто, в области где хранится строка нужно изменить обыкновенной записью саму строку. Например, вот так (для вашей программы):

Code: Select all

mov byte [string],'Ф'
тогда при следующей перерисовке Тестовая строка станет Фестовой (перерисовку можно и самому вызвать в таком случае).
Однако, нехорошо так делать потому что у вас написано что эти строки -

Code: Select all

; Константы
так что менять их не стоит.

Вместо этого следует добавить ещё одну строку, ту, на которую вы хотите изменить старую:

Code: Select all

string2   db   'Фестовая строка',0
а также переменную, которая будет служить указателем на правильную строку, например, так (после строк, пожалуйста):

Code: Select all

; Переменные

strpointer dd string
тут мы его сразу же и инициализируем, чтобы он сразу на корректную строку указывал. Тогда, в случае если нам потребуется изменить строку с тестовой на фестовую, мы просто сделаем это:

Code: Select all

mov dword [strpointer], string2
Только работать это не будет, если мы по прежнему будем использовать:

Code: Select all

mcall   4, <30,10>, 0x80000000, string
вместо этого нужно применить что-то вроде:

Code: Select all

mcall   4, <30,10>, 0x80000000, [strpointer]
Признаться, я не очень хорошо поню как устроен макрос mcall, но вроде так сойдёт.

Re: Помогите новичку

Posted: Wed Mar 11, 2015 3:09 pm
by gc986
Gluk wrote: Если я ничего не путаю, у нас получается (не забываем ещё 1 на 0xBE сменить):

Code: Select all

button_event:
   mcall 17
   cmp  ah, 0xBE
   je   close_program
   jmp   wait_event
и программа не будет завершаться по крестику, а только по вашей кнопке
Заработало :D

Re: Помогите новичку

Posted: Wed Mar 11, 2015 3:41 pm
by gc986
Gluk wrote: mov dword [strpointer], string2
Что означают квадратные скобки?

Как перевести число в строку? Хочу попробовать время выводить на экран ))

Re: Помогите новичку

Posted: Wed Mar 11, 2015 4:13 pm
by lev
В какое-то время в macros.inc был добавлен макрос "header" и все программы/примеры использовавшие метку "header" перестали компилироваться как задумывалось.
Добавьте "purge header" после строки 'include "macros.inc"', чтобы данный макрос не влиял, или переименуйте "header" в паре мест самой программы во что-нибудь другое.

Re: Помогите новичку

Posted: Wed Mar 11, 2015 4:16 pm
by Gluk
gc986 wrote:Что означают квадратные скобки?
Значат просто записать по адресу, написанному в квадратных скобках :) сделано так для того, чтобы если в адресе участвует регистр - не путать, куда записывать, в регистр или по адресу, куда он указывает. Так что адрес всегда в квадроскобках, когда работаем со значением.
gc986 wrote:Как перевести число в строку? Хочу попробовать время выводить на экран ))
отличные стремление и вопрос!

время мы скорее всего будем получать посредством системной функции 3 http://wiki.kolibrios.org/wiki/SysFn03/ru

Code: Select all

mcall 3
Не буду сюда копировать оттуда информацию, там формат хорошо описан. У нас стоит задача из этого формата получить строку, содержащую время. Сначала заготовим шаблон для того чтобы его заполнить в дальнейшем, в области данных (где переменные) пишем:

Code: Select all

timeline db '00:00:00',0
на самом деле тут главное двоеточия, остальное мы планируем перезаписать всё равно. Эту же строку можно выводить куда-нибудь как обычно, разумеется, а сейчас посмотрим как её обновлять.

Результат функции 3 сохраняется в регистре eax, с ним и будем работать.
сперва заполним поле единиц часов (потому что почему бы и нет), часы у нас хранятся как написано в ссылке в первом байте регистра eax, а значит в регистре al, единицы часов - в его младшем полубайте. Но да, там хранится только цифра. Чтобы превратить её в символ цифры, вспомним что в кодовых таблицах цифры идут подряд, начиная с нуля. Значит, если мы прибавим число к символу нуля, мы получим символ цифры. Однако! У нас в al ещё и десятки часов мешаются. Похоже нам понадобится ещё и буферный регистр для всяких махинаций. Пусть это будет bl, потому что он прикольный, похож на ы.

Code: Select all

; копируем в bl часы
mov bl, al
; удаляем десятки часов
and bl, 0x0F
; число->цифра
add bl, '0'
; сохраняем в строку
mov byte [timeline+1], bl
Дальше прикольно, не будем отказываться от предыдущей схемы, чтобы можно было её в цикл свернуть при желании. Для этого сместим весь eax вправо на 4 бита, вот так:

Code: Select all

shr eax, 4
Теперь в младшем полубайте al у нас десятки часов, круто, да? Ну тогда, очевидно:

Code: Select all

; копируем в bl десятки часов
mov bl, al
; удаляем единицы минут
and bl, 0x0F
; число->цифра
add bl, '0'
; сохраняем в строку
mov byte [timeline+0], bl
Ну и так далее:

Code: Select all

shr eax, 4
mov bl, al
and bl, 0x0F
add bl, '0'
mov byte [timeline+4], bl

Code: Select all

shr eax, 4
mov bl, al
and bl, 0x0F
add bl, '0'
mov byte [timeline+3], bl

Code: Select all

shr eax, 4
mov bl, al
and bl, 0x0F
add bl, '0'
mov byte [timeline+7], bl

Code: Select all

shr eax, 4
mov bl, al
and bl, 0x0F
add bl, '0'
mov byte [timeline+6], bl
и готово. В цикл мне лень сворачивать, а формальная отговорка - возможная потеря прозрачности объяснения =)

Re: Помогите новичку

Posted: Wed Mar 11, 2015 4:38 pm
by gc986
Gluk wrote: и готово. В цикл мне лень сворачивать, а формальная отговорка - возможная потеря прозрачности объяснения =)
Большое спасибо! Теперь у меня вечер занят полезным делом :)

Re: Помогите новичку

Posted: Thu Mar 12, 2015 9:31 am
by gc986
Gluk wrote: и готово. В цикл мне лень сворачивать, а формальная отговорка - возможная потеря прозрачности объяснения =)
Уф.... всё получилось просто идюально ))) Приложения написанные на асме постепенно перестают быть для меня абсолютной магией :D
Назрели вопросы:
1) Я повесил обновление времени на обработчик нажатия на кнопку, чтобы сделать время постоянно обновляющимся необходимо создать вечный цикл?
2) В учебнике написано что and - оператор логического умножения. Не могли бы вы по подробнее написать зачем и как используется эта команда?
3) Зачем складывать с '0', ведь число +0 это то же самое число или здесь другая логика?
4) Каждый символ в строке занимает 1 байт? (никогда не обращал на это внимание при программировании на языках высокого уровня)
5) Пользуюсь этим учебником (там промелькнуло TASM), для FASM он подойдёт? - http://www.kolasc.net.ru/cdo/programmes ... er/tc.html
6) Не совсем понимаю как работает главный цикл программы

Code: Select all

wait_event:
   mcall   10
   dec   eax
   jz   redraw
   dec   eax
   jz   key
   cmp   eax,3
   jz   button_event
Постоянно происходит вызов системной функции 10, и дальше перебор вариантов действий. Как система узнаёт что произошло событие обновления экрана, а не нажатия на кнопку например?

Re: Помогите новичку

Posted: Thu Mar 12, 2015 11:17 am
by Gluk
gc986 wrote: 1) Я повесил обновление времени на обработчик нажатия на кнопку, чтобы сделать время постоянно обновляющимся необходимо создать вечный цикл?
совершенно верно что нужен вечный цикл - но его не нужно создавать, он уже есть! Этот вопрос я рассмотрю разом с этим:
gc986 wrote: 6) Не совсем понимаю как работает главный цикл программы

Code: Select all

wait_event:
   mcall   10
   dec   eax
   jz   redraw
   dec   eax
   jz   key
   cmp   eax,3
   jz   button_event
Постоянно происходит вызов системной функции 10, и дальше перебор вариантов действий. Как система узнаёт что произошло событие обновления экрана, а не нажатия на кнопку например?
Давайте посмотрим как он работает. Из описания системной функции 10 http://wiki.kolibrios.org/wiki/SysFn10/ru мы знаем как она работает: при вызове выполнение программы приостанавливается, покуда не произойдёт событие, связанное с программой. Как только событие происходит, система "отпускает" программу и она продолжает выполнение, с одним изменением - в регистр eax записывается код произошедшего события. То есть, например, если нажата кнопка, в eax будет число 3. Вот мы и сравниваем значение eax с разными константами, если в eax единица например - перерисовываем окно, и после возвращаемся обратно к ожиданию события. Как система узнаёт что за событие - нам не важно, нам важно только как об этом узнаёт программа, ну вот я и описал вроде) надеюсь правильно понял вопрос.
Теперь что касается первого вопроса, про бесконечный цикл. Главный цикл программы уже является бесконечным циклом, в который мы можем как раз добавить вызов процедуры обновления времени. Посмотрим что нам нужно сделать для обновления: во-первых, пересчитать строку времени, во-вторых - перерисовать окно (на самом деле как-то возможно частичное обновление окна, но я так ни разу не делал, боюсь обмануть). И это надо делать периодически (или чаще). Один из вариантов как этого можно добиться (далеко не самый правильный вариант - но должно по крайней мере работать) следующий:

Code: Select all

wait_event:
   ; вместо сисфункции 10 применим http://wiki.kolibrios.org/wiki/SysFn23/ru
   ;работает как 10я за одним исключением, после 0.5 секунд (в данном случае)
   ;отпускает программу, записывая в eax значение 0.
   mcall   23, 50
   ; dec для сравнения с нулём не годится, используем cmp
   cmp  eax, 0
   ; тут я предполагаю что процедура обновления времени называется update_time
   ;и заканчивается командой jmp redraw
   jz   update_time
   dec   eax
   jz   redraw
   dec   eax
   jz   key
   cmp   eax,3
   jz   button_event
Ну вроде как-то так, теперь если программу не "вешать" постоянным вызовом событий (например, зажиманием кнопки клавиатуры) - время должно обновляться
gc986 wrote:2) В учебнике написано что and - оператор логического умножения. Не могли бы вы по подробнее написать зачем и как используется эта команда?
конечно могу. Тем более что для этого мне нужно всего лишь скопировать практически готовый ответ из этого самого учебника:
Применение:
Команда and используется для логического умножения двух операндов. Результат операции помещается по адресу первого операнда. Эту команду удобно использовать для принудительной установки или сброса определенных битов операнда.
Например, преобразуем двузначное упакованное BCD-число в его символьный эквивалент.
дальше идёт кстати код, который (примерно) я изобретал в предыдущем ответе :) там чуть меньше комментариев правда, может мне учебник написать :D
В общем, у нас тут как раз применение для принудительного сброса определённых битов. Вот есть bl, в нём допустим значение 0x23 (это значит 23 часа пускай). Нам нужно получить символ '3' (оставим пока в покое десятки). Для этого нужно удалить 0x20 из 0x23. Как же это сделать? Можно вычесть 0x20 из 0x23. Но программа ведь не знает что там именно два десятка часов! Поэтому воспользуемся логическими операциями, например and. Что она делает? Для каждого бита операндов выполняет следующее: если у обоих операндов текущий бит равен 1, то вернуть 1, иначе вернуть 0. Возвращает в первый операнд. Как это можно использовать? Посмотрим на наше число 0x23 в бинарном виде: 0b00100011. Что будет если мы съandим его с, например, 0b00001111 (0x0f)? Совершенно верно, там где у второго операнда 0 - у результата будет 0, а где 1 - там результат будет такой же, как в первом операнде! Значит получим 0b00000011, а это число 0x03 или просто 3! Как удачно подвернулся следующий вопрос:
gc986 wrote:3) Зачем складывать с '0', ведь число +0 это то же самое число или здесь другая логика?
Давайте продолжим мучать наш bl, который содержит уже 0x03, или 3. Если вы запишете это значение в какую-нибудь строку, выводящуюся потом на экран (попробуйте!), вы увидите вместо символа '3' что-то другое. Что именно - давайте посмотрим вместе вот тут https://ru.wikipedia.org/wiki/ASCII - упс, похоже это вообще какой-то служебный символ, и я полагаю на выводе будет пробел или кракозябра какая. Что же делать, как же быть, как нам тройку выводить... А посмотрим на таблицу снова, и найдём там символ тройки - вот же он, с кодом 0x33. То есть чтобы вывести символ '3' надо к числу 0x03 добавить число 0x30. Но я не очень люблю магические числа, где гарантия что через лет пять вы вспомните что это за число такое? Потому то я и прибавляю к нашему bl код символа '0' (видите, он в кавычках - значит это именно код символа, равный 0x30, а не число 0!), очевидно для 0x03 мы получим тогда 0x33, то есть '3'.
gc986 wrote: 4) Каждый символ в строке занимает 1 байт? (никогда не обращал на это внимание при программировании на языках высокого уровня)
ага, 1 байт в кодировке которая используется в Колибри. Бывают и другие кодировки - двубайтовые, четырёхбайтовые, и даже с переменным количеством байт. Но для вывода в Колибри именно однобайтовая кодировка обычно применяется. Первая половина кодовой таблицы - уже знакомая нам ASCII, вторая - национальные и дополнительные символы. Кстати, поделитесь - с какими языками высокого уровня вы знакомы? Зная это, мне проще будет показывать на конкретных примерах всякое.
gc986 wrote:5) Пользуюсь этим учебником (там промелькнуло TASM), для FASM он подойдёт? - http://www.kolasc.net.ru/cdo/programmes ... er/tc.html
ну я вот на него сослался, значит на что-то он годится :D А если серьёзно, можно использовать любой учебник, только смотрите чтобы там был описан ассемблер для x86. Отличаться у разных ассемблеров будет синтаксис, например насколько я помню квадратные скобочки чуть ли не только в FASM применяются, в других ассемблерах иначе задаётся то что работа идёт со значением а не с адресом. То есть команды такие же, только несколько иначе записываются и всё.

Re: Помогите новичку

Posted: Thu Mar 12, 2015 12:32 pm
by gc986
Gluk wrote:
gc986 wrote:5) Пользуюсь этим учебником (там промелькнуло TASM), для FASM он подойдёт? - http://www.kolasc.net.ru/cdo/programmes ... er/tc.html
ну я вот на него сослался, значит на что-то он годится :D А если серьёзно, можно использовать любой учебник, только смотрите чтобы там был описан ассемблер для x86. Отличаться у разных ассемблеров будет синтаксис, например насколько я помню квадратные скобочки чуть ли не только в FASM применяются, в других ассемблерах иначе задаётся то что работа идёт со значением а не с адресом. То есть команды такие же, только несколько иначе записываются и всё.
Большое спасибо! Честное слово, когда учился в техникуме ассемблер мне казался языком очень тяжёлым, а теперь интересным :D В повседневной жизни пишу приложения на Java (Android), а раньше Pascal (Delphi).
И всё таки я пока не совсем понимаю главный цикл... Происходит вызов системной функции 10, далее происходит уменьшение регистра на 1

Code: Select all

dec eax
Дальше идёт перемещение на нужную функцию, например обработка кнопок, перерисовка окна и т.д. А как именно это происходит не понимаю ))
По моей логике должно происходить следующим образом:

Re: Помогите новичку

Posted: Thu Mar 12, 2015 1:10 pm
by Gluk
gc986 wrote: И всё таки я пока не совсем понимаю главный цикл... Происходит вызов системной функции 10, далее происходит уменьшение регистра на 1

Code: Select all

dec eax
Дальше идёт перемещение на нужную функцию, например обработка кнопок, перерисовка окна и т.д. А как именно это происходит не понимаю ))
о, да это просто читерство. Легко можно было бы использовать:

Code: Select all

   cmp   eax, 0
   je   update_time
   cmp   eax, 1
   je   redraw
   cmp   eax, 2
   je   key
   cmp   eax, 3
   je   button_event
Теперь посмотрим как работает тот вариант:

Code: Select all

   cmp   eax, 0 ; вычитаем из eax 0 (не меняя значение eax), если результат= 0, устанавливаем флаг Z, а ещё флаг E
   jz   update_time ; если флаг Z установлен, переходим к update_time
 ; je   update_time ; <или так] если флаг E установлен, переходим к update_time
   dec   eax ; уменьшаем eax на 1, если результат= 0, устанавляваем флаг Z 
   jz   redraw ; если флаг Z установлен, переходим к redraw
   dec   eax ; уменьшаем eax на 1, если результат= 0, устанавляваем флаг Z 
   jz   key ; если флаг Z установлен, переходим к key
   dec   eax ; уменьшаем eax на 1, если результат= 0, устанавляваем флаг Z 
   jz   button_event ; если флаг Z установлен, переходим к button_event 
тоже работает, при этом меньше констант упомянуто в коде (нету 1, 2, 3 и т.д.).

Хотя раз уж мы добавили,

Code: Select all

cmp   eax, 0
то для однообразия может лучше и сменить всё на cmp