0 / 0 / 0
Регистрация: 22.01.2010
Сообщений: 87
1

Трюки для ASMатиков.

13.09.2010, 16:23. Показов 9333. Ответов 20
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Тем временем, чтобы коллективный разум совсем не задубел, загружу его полезной работой :)
Итак, имеем:
Код
LDi R16, X
LDi R17, Y
где X, Y - знаковые числа.
Задача проста: получить в R16 значение выражения (X-Y)/2.
На первый взгляд все просто, но в итоге... Решение выложу после некоторого количества догадок :)
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
13.09.2010, 16:23
Ответы с готовыми решениями:

Переменные и трюки над ими
Условие задачи : Условие такое что надо подобрать закономерность но я не могу снизу переменные и их...

Динамическая верстка. Трюки и навыки
Привет. Вариант 1. Есть простые трюки превращения разметки в объект. var string = '<div><input...

Рекурсия-Советы или Трюки
привет у меня скоро экзамен я хотел спросить как лучше всего отслеживать рекурсию или её запиывать...

Нужны сайты про C#, приемы, рецепты, трюки программирования
Не советуйте msdn или книгу. Справочник должен быть похож на другие стандартные справочники как у...

20
0 / 0 / 0
Регистрация: 27.06.2010
Сообщений: 405
13.09.2010, 17:17 2
Для знаковых чисел:
Код
sub r16, r17
ror r16
Для беззнаковых:
Код
sub r16, r17
asr r16
0
0 / 0 / 0
Регистрация: 26.01.2010
Сообщений: 273
13.09.2010, 17:39 3
Цитата Сообщение от miyvir
Для знаковых чисел:
Код:
sub r16, r17
ror r16
miyvir теряете знак при сдвиге.

Сложность задачи сильно преувеличена. Это не трюки, а так, шуточки. Трюков вы еще не видели = ))
Код
sub r16,r17
BST r16,7
lsr R16
BLD r16,7
0
0 / 0 / 0
Регистрация: 22.01.2010
Сообщений: 87
13.09.2010, 17:45 4
Цитата Сообщение от SOWushko
Сложность задачи сильно преувеличена. Это не трюки, а так, шуточки. Трюков вы еще не видели = ))
Код:
sub r16,r17
BST r16,7
lsr R16
BLD r16,7

Тоже неправильный код, фэйлит при X= -103, Y=72 :)
0
0 / 0 / 0
Регистрация: 07.03.2010
Сообщений: 233
13.09.2010, 18:06 5
ASM не увлекаюсь но судя по всему нужно сначала поделить, а потом уже вычетать..
0
0 / 0 / 0
Регистрация: 26.01.2010
Сообщений: 273
13.09.2010, 18:17 6
Цитата Сообщение от ZhikSooM
Тоже неправильный код, фэйлит при X= -103, Y=72 :)
да, действительно, из за переполнения, потеряется бит. Что в принципе не делает задачу сложнее )
Код
BST r16,7
lsr R16
BLD r16,7
BST r17,7
lsr R17
BLD r17,7
sub r16,r17
Трюки начинаются тогда, когда начинаем делить 16-32 разрядные знаковые числа, вот там трюки так трюки.
Числа с плав. запятой тоже ничего.
0
0 / 0 / 0
Регистрация: 22.01.2010
Сообщений: 87
13.09.2010, 18:34 7
Цитата Сообщение от mos80
ASM не увлекаюсь но судя по всему нужно сначала поделить, а потом уже вычетать..
Вариант неплохой, но округление там будет немного не красивое
0
0 / 0 / 0
Регистрация: 03.11.2012
Сообщений: 9
13.09.2010, 18:46 8
Цитата Сообщение от SOWushko
Код:
BST r16,7
lsr R16
BLD r16,7
BST r17,7
lsr R17
BLD r17,7
sub r16,r17

Команды сохранения/восстановления флагов и логического сдвига тут можно заменить командой ASR
0
0 / 0 / 0
Регистрация: 22.01.2010
Сообщений: 87
13.09.2010, 18:58 9
Ну что ж, смотрите мой вариант:
Код
sub R16, R17
brvc PC+2
sec
brbc 4, PC+2
sec
ror R16
Честное вычитание, но с хитрой коррекцией (хотя никакой хитрости тут нету, все по правилам).
0
0 / 0 / 0
Регистрация: 18.03.2010
Сообщений: 2,230
13.09.2010, 21:45 10
а вот так не покатит?
Код
ldi r18,0x80
add r16,r18
add r17,r18
sub r16, r17
ror r16
0
0 / 0 / 0
Регистрация: 13.08.2010
Сообщений: 58
14.09.2010, 04:17 11
Цитата Сообщение от ZhikSooM
Ну что ж, смотрите мой вариант:
Код:
sub R16, R17
brvc PC+2
sec
brbc 4, PC+2
sec
ror R16
Честное вычитание, но с хитрой коррекцией (хотя никакой хитрости тут нету, все по правилам).Не работает при X=1, Y=-2. Чтоб заработало, надо после sub поставить clc.

Цитата Сообщение от Ymk
а вот так не покатит?
Код:
ldi r18,0x80
add r16,r18
add r17,r18
sub r16, r17
ror r16

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

Вот мой вариант:
Код
   sub    r16, r17
clc
brpl   PC+2
sec
ror   r16
0
0 / 0 / 0
Регистрация: 22.01.2010
Сообщений: 87
16.09.2010, 00:39 12
qbyt, ваш код тоже не рабочий - последние 4 команды в итоге вырождаются в ASR R16.
А вот код Инка потряс - просто и со вкусом!!!
0
0 / 0 / 0
Регистрация: 18.03.2010
Сообщений: 2,230
16.09.2010, 00:41 13
шпашыбо! это мой дебют на avr-asm:)
а призы будут?:)))))
0
0 / 0 / 0
Регистрация: 13.08.2010
Сообщений: 58
16.09.2010, 03:48 14
Цитата Сообщение от ZhikSooM
qbyt, ваш код тоже не рабочий - последние 4 команды в итоге вырождаются в ASR R16...
Да, согласен. Фишка вот в чём. Для примеров, в частности, для X= -103 и Y=72, происходит переполнение динамического диапазона промежуточного результата. Получаем, X-Y=-103–72=-175. Для типа char числа должны быть в диапазоне:
положительные: 1...127, отрицательные -1...-128. Как видно, промежуточный результат вываливается за пределы представления отрицательных чисел. Т.е. решение вида:
Код
   sub r16, r17
ror r16
работает только, если промежуточный результат не выходит за границы представления чисел. Получается, что X и Y для этого примера могут принимать следующие значения: положительные: 1...62, отрицательные -1...-64.

Мысль mos80 о том, что сперва делим, а потом вычитаем, так же гуд. Вот, что получается:
Код
   asr   r16
asr   r17
sub   r16, r17
Решение от Ymk можно оптимизировать, заменив регистр R18 на арифметику с константой:
Код
   subi   r16,128
subi   r17,128
sub   r16,r17
ror   r16
Если разность X и Y, представленных как char, положительна, то флаг S, бит 4 регистра статуса, всегда будет в “0", если отрицательна, то всегда флаг S будет выставлен. Собственно, вот код:
Код
   sub   r16, r17
clc
brbc 4, PC+2
sec
ror r16
Получается, что код, в котором сперва делим, а потом вычитаем – самый оптимальный, всего 3 команды.
0
0 / 0 / 0
Регистрация: 17.02.2010
Сообщений: 192
16.09.2010, 04:51 15
А что ZhikSooM подразумевал под немного не красивым округлением?
0
0 / 0 / 0
Регистрация: 18.03.2010
Сообщений: 2,230
16.09.2010, 10:24 16
Цитата Сообщение от qbyt
Мысль mos80 о том, что сперва делим, а потом вычитаем, так же гуд. Вот, что получается:
x=0, y=1
должно быть: (0 - 1)/2 = (-1)/2 = -1.
будет: (0/2) - (1/2) = (0) - (0) = 0.

разное округление как бы.
Цитата Сообщение от qbyt
Решение от Ymk можно оптимизировать, заменив регистр R18 на арифметику с константой:
вот же факиншыт! искал же я с константой, не нашел. omd и or видел,а eor нет. и сложения с вычитанием не нашел...
залез щас в даташит и... нашел SUBI только со второго раза:)))
0
0 / 0 / 0
Регистрация: 07.03.2010
Сообщений: 233
16.09.2010, 12:59 17
Цитата Сообщение от Ymk
Цитата Сообщение от qbyt
Мысль mos80 о том, что сперва делим, а потом вычитаем, так же гуд. Вот, что получается:
x=0, y=1
должно быть: (0 - 1)/2 = (-1)/2 = -1.
будет: (0/2) - (1/2) = (0) - (0) = 0.

А почему (-1)/2 = -1 а (1/2) = (0) ?
Разве знак как-то влияет?
0
0 / 0 / 0
Регистрация: 22.01.2010
Сообщений: 87
16.09.2010, 13:27 18
Машинное округление до меньшего будет правильнее.
0
0 / 0 / 0
Регистрация: 18.03.2010
Сообщений: 2,230
16.09.2010, 18:41 19
mos80, еще как влияет!
0
0 / 0 / 0
Регистрация: 22.01.2010
Сообщений: 87
17.09.2010, 01:32 20
Итак, начнем разбор полетов.
Первым идею подал miyvir:
Код
sub r16, r17
ror r16
Этот код совершенно не подходит для нашего случая, но он эксплуатирует одну идею: прямое использования флага переполнения как девятого бита числа. Эта фишка хорошо прокатывает для сложения беззнаковых числел и последующего деления на 2:
Код
add r16, r17
ror r16
Такой код работал бы идеально: при сложении может произойти переполнение, при этом устанивится флаг C, что аналогично установке 9-го бита в числе большей разрядности. А команда ROR сдвигает результат вправо на один бит, а содержимое флага (считай что 9-й бит числа) ставит на место 8-го бита - получается тоже такой своеобразный сдвиг (2-й бит на место 1-го, 3-й - на 2-е, ... , 9-й - на 8-е).

Следующая идея была подана г-ном SOWushko:
Код
sub r16,r17
BST r16,7
lsr R16
BLD r16,7
Этот код был сильно избыточен, т.к. три последние команды аналогичны команде ASR R16.
А эта команда, как известно, не учитывает каким-либо образом содержимое флагов и просто делит знаковое число на 2.

Наверное сразу непонятно, какие вообще проблемы могут возникнуть с таким простым выражением?
Сейчас я постараюсь объяснить.

Начнем с представления знаковых чисел в пределах одного байта. Об этом кратенько писал Ди в заметке про флаг V, но сейчас об этом по-подробнее.
Тут можно провести аналогию с Земным шаром. Предположим, вы стоите на экваторе на стыке восточного и западного полушарий. Это место считаем нулем. Чуть шаг влево - вы уже на западном, вправо - на восточном. Причем ваше положение определяется не как +- пройденный путь, а как полный путь через восточное полушарие, по часовой стрелке. Т.е. если вы шагнули на 17 метров на запад, то ваша координата не -17 считая от нуля, а (Длина экватора минус 17). Ведь и правда - чтобы прийти к вам из нуля, можно шагнуть 17 метров на запад, а можно обогнуть весь экватор и подойти к вам с другой стороны. На первый взгляд бредово, но при отсутствии понятия "лево-право" очень пригодится.
Так вот, в микроконтроллерах (а в прочем и во всех ЭВМ) такая же ситуация - они не знают этих понятий и пользуются такой системой определения расстояний. Но, несмотря на то, что "лево-право" МК неизвестны, у него есть отдельные команды для движения в разные стороны - это, как можно догадаться, сложение и вычитание.

Как уже стало понятно, микроконтроллер не знает положительных чисел - они есть только у нас в головах, а в МК они хранятся в виде такого "полного" расстояния, при этом явное деление на "полушария" происходит при помощи самого старшего бита числа. Действительно, имеется ровно половина чисел (0..127), в которых этот бит не установлен, и половина (128..255), где он установлен. Бит установлен - "западное" полушарие (отрицательные числа), нету бита - "восточное" (положительные).

С этим разобрались. Теперь подходим ближе к нашей проблеме, которую я сейчас сформулирую.
Дело в том, что есть еще одна точка раздела восточного и западного полушария - она находится в точке с противоположной стороны земного шара, диаметрально противоположно точке нуля. Так вот, если мы близко подберемся к этой точке, например, со стороны восточного "положительного" полушария, то неосторожное прибавление некоторого числа к нашему текущему положению переступит эту границу и мы внезапно окажимся в западном "отрицательном" полушарии! Та же самая хрень может быть и при вычитании. Беда в том, что мы не хотели такого развития событий, но у процессора нету сведений о том, в каком полушарии мы находились до сложения (вычитания). Ведь по логике, если у нас до сложения было положительное число (восточное полушарие), и мы прибавили положительное число, то и на выходе должно быть положительное число (восточное полушарие)! А у нас в результате - западное!
Хотя... нет, сведения о прошлом положении есть! И это - флаг V во флаговом регистре. Короче говоря, если он установлен, то значит произошел переход в другое полушарие, если нет - то нет (Но! Переход через нулевую точку это флаг не учитывает и не отслеживает, т.к. это "честный" переход без побочных эффектов: к отрицательному прибавили бОльшее положительное - перешли из западного полушария в восточное - все в норме! Зато этот переход через ноль отслеживается во флаге C) . И это поможет нам определить, каким должен быть результат - положительным или отрицательным.
В принципе, этого флага достаточно для компенсации этого багафичи - мы должны сделать следующее:
1)Смотрим на последний бит результата - он определяет полушарие (знак числа), как я уже сказал.
2)Смотрим на бит V во флаговом регистре.
3)Теперь думаем:
-Если бит V установлен, то тут что-то неладное и нужна коррекция. Коррекция в какую сторону? Вот тут то мы и..
- Снова смотрим на последний бит результата. Если он установлен, то мы перескачили из восточного полушария в западное (перешагнули эту чертову границу), значит нам надо вернуться в западное полушарие. Фича в том, что просто вернуться нельзя - мы как-бы вылезли за пределы байта и нам нужен 9-й бит для нашего числа. Вот этот бит и будет равен нулю, т.к. в 9-тибитном числе он теперь указатель "полушария", а не 8-й бит. Равен нулю - значит мы в восточном полушарии и ниипет. А вот..
-Если бит V установлен, но результат положительный (последний бит результата - ноль, результат в восточном полушарии), то значит мы в процессе отнимания от отрицательного числа, которое стояло у границы этого раздела полушарий, перелезли эту границу, и вместо того, чтобы стать еще более отрицательнее, внезапно стали положительными. Непорядок. Именно в этом случае мы должны установить наш 9-й бит в единицу, которая намекнет - "мы должны быть в западном полушарии как до, так и после вычитания".
-А если бит V не установлен? Значит мы не вылезли за пределы одного байта и никакие 9-е биты нам не нужны. Но все же, каким будет наше 8-мибитное число в 9-тибитном пердставлении? Ясен пень, все таким же, но что будет в 9-м бите? А в нем будет значение, определяющее текущее полушарие. Т.к. это значение сейчас в 8-м бите, то нам просто надо скопировать его в 9-й бит!

Мда, чтоб определить, какое же у нас число - положительное или отрицательное, пришлось повозиться. Но.. Я вас обрадую!!! Процессор AVR уже все сделал за вас - прошелся по этим пунктам и определил, какое же значение стоит в 9-м бите (несмотря на то, нужен он или не нужен) результата. И это будет значение флага S во флаговом регистре.
Теперь, если надо, с ним можно делать что угодно: хочешь - копируй его в другой регистр и приводи 9-тибитное число в 16-битное (целых 7 бит просрать впустую, надо же!), а можно скопировать этот бит во флаг C и использовать его для деления результата на 2, как в самом первом примере. Следовательно, полностью рабочий код будет таким (первый предложил qbyt, правда после небольшой наводки):
Код
  sub   r16, r17
clc
brbc 4, PC+2
sec
ror r16
Подробнее:
Код
clc
очищает флаг С во флаговом регистре, т.к. мы будем "копировать" в него содержимое флага S. Вот только это не настоящее копирование с полным замещением содержимого, как командой MOV, а условная установка этого флага, и перед ней надо иметь заранее известное значение в этом флаге.
Код:brbc 4, PC+2
sec
Это сам код условной установки флага С в зависимости от содержимого флага S. Страшная команда brbc 4, PC+2 ничто иное как проверка флага S на установленность (создатели компилятора не удосужились выделить удобочитаемую мнемонику команде проверки этого флага, как, например, флагу С: BRCS (BRanch if Carry Set)). Если он не установлен - то прыгаем на две команды вниз и флаг C остается чистым (не зря же я говорил, что надо точно его знать содержимое перед этим делом!). Еслм установлен - то идет на следующую команду, которая и устанавливает флаг С.
Ну а последняя команда
Код:ROR R16
делает уже знакомые нам вещи: все биты сдвигает вправо на одну позицию, а бит из флага С ставит на восьмое, пустое место (т.к. сидевший на 8-м месте бит ушел на 7-е), и в итоге получается результат, деленный на 2.
0
17.09.2010, 01:32
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
17.09.2010, 01:32
Помогаю со студенческими работами здесь

Лидеры рейтинга. Ловкие трюки или большие деньги?
Помогите мне, пожалуйста, найти ответ на такой вопрос. Моему сайту по непознанному более года,...

Какие есть хитрости и трюки, уменьшающие размер кода и увеличивающие быстродействие
скажите какие есть хитрости и трюки в языкe c++ уменьшающие размер кода и увеличивающие...

'BaT команды и "трюки"' >в> делфи - как?
https://www.cyberforum.ru/delphi-beginners/thread336099.html#post1865968 Собственно тема вот, не...

BaT команды и "трюки" в делфи - как?
Так.. Допустим мне нужно запустить файл, два... BAT Set variant=Variant1 :: Set...

Кошка Таня показывает трюки. Борис Иванович прибил к стене сетку: a клеток в высоту и b клеток в ширину
Кошка Таня показывает трюки. Борис Иванович прибил к стене сетку: a клеток в высоту и b клеток в...

Подскажите пожалуйста IDE для линукса (например, для кали-линукса) для новичка для обучения программированию на си++
Сейчас обучаюсь стандарту си++ 2011. Подскажите новичку, чего выбрать? Есть небольшой опыт работы в...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru