Board.KolibriOS.org

Official KolibriOS board
It is currently Tue Sep 22, 2020 1:55 pm

All times are UTC+03:00




Post new topic  Reply to topic  [ 1140 posts ]  Go to page Previous 164 65 66 67 6876 Next
Author Message
PostPosted: Wed Mar 11, 2015 11:32 am 
Offline
User avatar

Joined: Mon Apr 16, 2007 6:38 pm
Posts: 1222
если подробно, то жаль нет уточнения что за языки высокого уровня вы используете, чтобы объяснить. Допустим, это Python:
Code:
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, значит кнопку никто не нажимал. Или нажимал?...

_________________
И мы уже давно не пешки,
Мы пули, мы орлы, и решки!
Война ютит бинарный код,
Умри, или иди вперед!


Top
   
PostPosted: Wed Mar 11, 2015 12:53 pm 
Offline
User avatar

Joined: Sat Apr 20, 2013 6:43 am
Posts: 29
Gluk wrote:
если коротко, следует заменить
Code:
cmp   eax,3

на
Code:
dec   eax

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


Top
   
PostPosted: Wed Mar 11, 2015 1:11 pm 
Offline
User avatar

Joined: Mon Apr 16, 2007 6:38 pm
Posts: 1222
gc986 wrote:
Спасибо!
Я хотел закрывать экран по нажатию на кнопку, сейчас закрытие происходит и по кнопке и по крестику. Как определять что событие пришло от конкретного компонента (кнопки на экране), а не от системной кнопки закрытия? Нужно её идентификатор указывать?
С помощью какой инструкции можно поменять текст на надписи?

Всегда пожалуйста!
думаю, в данном случае следует применить системную функцию 17, о которой можно прочитать например вот на этой странице http://wiki.kolibrios.org/wiki/SysFn17/ru . Вызывать её наверное следует в участке кода, который выполняется когда нажата кнопка, то есть, скорее всего, в процедуре button_event. Если непонятно как применить, спрашивайте свободно

_________________
И мы уже давно не пешки,
Мы пули, мы орлы, и решки!
Война ютит бинарный код,
Умри, или иди вперед!


Top
   
PostPosted: Wed Mar 11, 2015 1:41 pm 
Offline
User avatar

Joined: Sat Apr 20, 2013 6:43 am
Posts: 29
Gluk wrote:
Всегда пожалуйста!
думаю, в данном случае следует применить системную функцию 17, о которой можно прочитать например вот на этой странице http://wiki.kolibrios.org/wiki/SysFn17/ru . Вызывать её наверное следует в участке кода, который выполняется когда нажата кнопка, то есть, скорее всего, в процедуре button_event. Если непонятно как применить, спрашивайте свободно

Т.е. необходимо произвести сравнение содержимого регистра eax с 17, если равны, то ничего не делать, иначе производить выход из приложения.
Code:
cmp eax, 17
jne close_program
jmp wait_program

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


Top
   
PostPosted: Wed Mar 11, 2015 2:39 pm 
Offline
User avatar

Joined: Mon Apr 16, 2007 6:38 pm
Posts: 1222
не совсем. Сначала нужно вызвать системную функцию:
Code:
mcall   17

сразу после этого в регистре ah очутится идентификатор кнопки, которая нажата.
идентификатор (упрощённо говоря) это то, что у вас в коде:
Code:
mcall   8, <30,50>, <30,20>, 1, 0xf0f0f0

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


Возвращаясь к нашей button_event: надо будет после вызова 17й функции сравнить ah с 0xBE:
Code:
cmp ah, 0xBE

вместо
Code:
cmp eax, 17
.

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

вместо
Code:
jne close_program
.

Если я ничего не путаю, у нас получается (не забываем ещё 1 на 0xBE сменить):
Code:
button_event:
   mcall 17
   cmp  ah, 0xBE
   je   close_program
   jmp   wait_event

и программа не будет завершаться по крестику, а только по вашей кнопке

_________________
И мы уже давно не пешки,
Мы пули, мы орлы, и решки!
Война ютит бинарный код,
Умри, или иди вперед!


Top
   
PostPosted: Wed Mar 11, 2015 3:03 pm 
Offline
User avatar

Joined: Mon Apr 16, 2007 6:38 pm
Posts: 1222
gc986 wrote:
С помощью какой инструкции можно поменять текст на надписи?

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

Вместо этого следует добавить ещё одну строку, ту, на которую вы хотите изменить старую:
Code:
string2   db   'Фестовая строка',0
а также переменную, которая будет служить указателем на правильную строку, например, так (после строк, пожалуйста):
Code:
; Переменные

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


Только работать это не будет, если мы по прежнему будем использовать:
Code:
mcall   4, <30,10>, 0x80000000, string
вместо этого нужно применить что-то вроде:
Code:
mcall   4, <30,10>, 0x80000000, [strpointer]

Признаться, я не очень хорошо поню как устроен макрос mcall, но вроде так сойдёт.

_________________
И мы уже давно не пешки,
Мы пули, мы орлы, и решки!
Война ютит бинарный код,
Умри, или иди вперед!


Last edited by Gluk on Wed Mar 11, 2015 3:15 pm, edited 1 time in total.

Top
   
PostPosted: Wed Mar 11, 2015 3:09 pm 
Offline
User avatar

Joined: Sat Apr 20, 2013 6:43 am
Posts: 29
Gluk wrote:
Если я ничего не путаю, у нас получается (не забываем ещё 1 на 0xBE сменить):
Code:
button_event:
   mcall 17
   cmp  ah, 0xBE
   je   close_program
   jmp   wait_event

и программа не будет завершаться по крестику, а только по вашей кнопке


Заработало :D


Top
   
PostPosted: Wed Mar 11, 2015 3:41 pm 
Offline
User avatar

Joined: Sat Apr 20, 2013 6:43 am
Posts: 29
Gluk wrote:
mov dword [strpointer], string2


Что означают квадратные скобки?

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


Top
   
PostPosted: Wed Mar 11, 2015 4:13 pm 
Offline

Joined: Tue Oct 05, 2010 6:05 pm
Posts: 216
В какое-то время в macros.inc был добавлен макрос "header" и все программы/примеры использовавшие метку "header" перестали компилироваться как задумывалось.
Добавьте "purge header" после строки 'include "macros.inc"', чтобы данный макрос не влиял, или переименуйте "header" в паре мест самой программы во что-нибудь другое.


Top
   
PostPosted: Wed Mar 11, 2015 4:16 pm 
Offline
User avatar

Joined: Mon Apr 16, 2007 6:38 pm
Posts: 1222
gc986 wrote:
Что означают квадратные скобки?
Значат просто записать по адресу, написанному в квадратных скобках :) сделано так для того, чтобы если в адресе участвует регистр - не путать, куда записывать, в регистр или по адресу, куда он указывает. Так что адрес всегда в квадроскобках, когда работаем со значением.

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

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

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

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

Результат функции 3 сохраняется в регистре eax, с ним и будем работать.
сперва заполним поле единиц часов (потому что почему бы и нет), часы у нас хранятся как написано в ссылке в первом байте регистра eax, а значит в регистре al, единицы часов - в его младшем полубайте. Но да, там хранится только цифра. Чтобы превратить её в символ цифры, вспомним что в кодовых таблицах цифры идут подряд, начиная с нуля. Значит, если мы прибавим число к символу нуля, мы получим символ цифры. Однако! У нас в al ещё и десятки часов мешаются. Похоже нам понадобится ещё и буферный регистр для всяких махинаций. Пусть это будет bl, потому что он прикольный, похож на ы.
Code:
; копируем в bl часы
mov bl, al
; удаляем десятки часов
and bl, 0x0F
; число->цифра
add bl, '0'
; сохраняем в строку
mov byte [timeline+1], bl


Дальше прикольно, не будем отказываться от предыдущей схемы, чтобы можно было её в цикл свернуть при желании. Для этого сместим весь eax вправо на 4 бита, вот так:
Code:
shr eax, 4

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

Ну и так далее:
Code:
shr eax, 4
mov bl, al
and bl, 0x0F
add bl, '0'
mov byte [timeline+4], bl

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

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

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


и готово. В цикл мне лень сворачивать, а формальная отговорка - возможная потеря прозрачности объяснения =)

_________________
И мы уже давно не пешки,
Мы пули, мы орлы, и решки!
Война ютит бинарный код,
Умри, или иди вперед!


Top
   
PostPosted: Wed Mar 11, 2015 4:38 pm 
Offline
User avatar

Joined: Sat Apr 20, 2013 6:43 am
Posts: 29
Gluk wrote:
и готово. В цикл мне лень сворачивать, а формальная отговорка - возможная потеря прозрачности объяснения =)


Большое спасибо! Теперь у меня вечер занят полезным делом :)


Top
   
PostPosted: Thu Mar 12, 2015 9:31 am 
Offline
User avatar

Joined: Sat Apr 20, 2013 6:43 am
Posts: 29
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:
wait_event:
   mcall   10
   dec   eax
   jz   redraw
   dec   eax
   jz   key
   cmp   eax,3
   jz   button_event

Постоянно происходит вызов системной функции 10, и дальше перебор вариантов действий. Как система узнаёт что произошло событие обновления экрана, а не нажатия на кнопку например?


Top
   
PostPosted: Thu Mar 12, 2015 11:17 am 
Offline
User avatar

Joined: Mon Apr 16, 2007 6:38 pm
Posts: 1222
gc986 wrote:
1) Я повесил обновление времени на обработчик нажатия на кнопку, чтобы сделать время постоянно обновляющимся необходимо создать вечный цикл?
совершенно верно что нужен вечный цикл - но его не нужно создавать, он уже есть! Этот вопрос я рассмотрю разом с этим:
gc986 wrote:
6) Не совсем понимаю как работает главный цикл программы
Code:
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:
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 - оператор логического умножения. Не могли бы вы по подробнее написать зачем и как используется эта команда?
конечно могу. Тем более что для этого мне нужно всего лишь скопировать практически готовый ответ из этого самого учебника:
Quote:
Применение:
Команда 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 применяются, в других ассемблерах иначе задаётся то что работа идёт со значением а не с адресом. То есть команды такие же, только несколько иначе записываются и всё.

_________________
И мы уже давно не пешки,
Мы пули, мы орлы, и решки!
Война ютит бинарный код,
Умри, или иди вперед!


Top
   
PostPosted: Thu Mar 12, 2015 12:32 pm 
Offline
User avatar

Joined: Sat Apr 20, 2013 6:43 am
Posts: 29
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:
dec eax

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


Attachments:
main_asm.png
main_asm.png [ 21.76 KiB | Viewed 1866 times ]
Top
   
PostPosted: Thu Mar 12, 2015 1:10 pm 
Offline
User avatar

Joined: Mon Apr 16, 2007 6:38 pm
Posts: 1222
gc986 wrote:
И всё таки я пока не совсем понимаю главный цикл... Происходит вызов системной функции 10, далее происходит уменьшение регистра на 1
Code:
dec eax

Дальше идёт перемещение на нужную функцию, например обработка кнопок, перерисовка окна и т.д. А как именно это происходит не понимаю ))
о, да это просто читерство. Легко можно было бы использовать:
Code:
   cmp   eax, 0
   je   update_time
   cmp   eax, 1
   je   redraw
   cmp   eax, 2
   je   key
   cmp   eax, 3
   je   button_event

Теперь посмотрим как работает тот вариант:
Code:
   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:
cmp   eax, 0

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

_________________
И мы уже давно не пешки,
Мы пули, мы орлы, и решки!
Война ютит бинарный код,
Умри, или иди вперед!


Top
   
Display posts from previous:  Sort by  
Post new topic  Reply to topic  [ 1140 posts ]  Go to page Previous 164 65 66 67 6876 Next

All times are UTC+03:00


Who is online

Users browsing this forum: No registered users and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Limited