| Разработка и ромхакинг > Ромхакинг и программирование |
| Нужна помощь по командам M68k |
| (1/6) > >> |
| DrMefistO:
Собственно вопрос: --- Код: ---ROM:00005AF6 tst.w d0 ROM:00005AF8 slt d0 --- Конец кода --- Что делает данная связка команд и как это будет выглядеть на C, Pascal? |
| Ti_:
Scc прописывание значения byte -$FF или 0 в зависимости от условия. scc (set if carry clear) - eсли carry clear - то $FF , если нет 0 scs (set if carry set) - если carry set- $FF , если нет то 0 и также с остальными (slt - set if lower) |
| DrMefistO:
Отдельно по взятым командам и я нашел инфу. Но от этого понятнее не стало. Мне нужно данную проверку реализовать на языке высокого уровня. А точнее не понимаю Lower чем что? Нуля? Но как word может быть меньше нуля? |
| Ti_:
--- Цитата: DrMefistO от 13 Сентябрь 2012, 13:41:47 ---А точнее не понимаю Lower чем что? Нуля? Но как word может быть меньше нуля? --- Конец цитаты --- Вроде может если от -$7FFF до -$FFFF . Blt Bge - знаковые Bcs Bcc - без знаковые Например когда делаешь сравнение cmpi.b #10,d0 и далее blt.s лучше ставить bcs.s а не blt - а то если d0 будет от $80 до $FF, то уже будет считаться меньше а не больше. |
| DrMefistO:
Вот именно, что дальше Бранчей нету вообще. Т.е. только установка d0. Добавлено позже: Для TST написано: --- Код: ---X Not affected. N Set if the operand is negative. Cleared otherwise. Z Set if the operand is zero. Cleared otherwise. V Always cleared. C Always cleared. --- Конец кода --- А для CLT: --- Код: ---LT Less Than N (+) V = 1 --- Конец кода --- Следовательно только N. |
| Ti_:
--- Цитата: DrMefistO от 13 Сентябрь 2012, 14:51:17 ---Вот именно, что дальше Бранчей нету вообще. Т.е. только установка d0. --- Конец цитаты --- tst.w d0 blt.s label move.b #0,d0 bra.s label2 label: move.b #$FF,d0 label2: тоже самое |
| DrMefistO:
Так как это переварить на язык высокого уровня? |
| Ti_:
--- Цитата: DrMefistO от 13 Сентябрь 2012, 14:51:17 ---А для CLT: --- Код: ---LT Less Than N (+) V = 1 --- Конец кода --- Следовательно только N. --- Конец цитаты --- Значит n - negative - а это отрицательные цисла - то есть от $8000 до $FFFF. Тогда и SMI или bmi - должно тоже самое давать. Добавлено позже: --- Цитата: DrMefistO от 13 Сентябрь 2012, 14:55:22 ---Так как это переварить на язык высокого уровня? --- Конец цитаты --- если бы знал их - сказал :) |
| DrMefistO:
--- Код: ---а это отрицательные числа - то есть от $8000 до $FFFF. --- Конец кода --- Не знал даже. Спасибо. Тогда более менее понятно: --- Код: ---var d0: word; ... if (d0 >= $8000) and (d0 <= $ffff) then d0 := $FF else d0 := $00; --- Конец кода --- Так? |
| Ti_:
--- Цитата: DrMefistO от 13 Сентябрь 2012, 15:00:36 --- --- Код: ---а это отрицательные числа - то есть от $8000 до $FFFF. --- Конец кода --- Не знал даже. Спасибо. Тогда более менее понятно: --- Код: ---if (d0 >= $8000) and (d0 <= $ffff) then d0 := $FF else d0 := $00; --- Конец кода --- Так? --- Конец цитаты --- Да наверное так, только еще надо смотреть чтобы в d0 менялся только младший байт. Хотя это может и не обязательно быть походу кода. Но scc меняют только 1байт. (а команды например moveq #8,d0 - но это уже 8bit sign-extened- то есть запишется longword 0000 0008) Добавлено позже: --- Цитата: DrMefistO от 13 Сентябрь 2012, 15:00:36 --- --- Код: ---а это отрицательные числа - то есть от $8000 до $FFFF. --- Конец кода --- Не знал даже. Спасибо. Тогда более менее понятно: --- Конец цитаты --- Незачто, также с mulu muls (muls знаковое умножение). lsr/asr - asr знаковый сдвиг. a0-a7 сами расширяются до longword при записи word. Ещё что-нить вроде movem.w (sp)+,d0-d2, расширяет хоть и загружает d0 word, но расшрияет его до longword. , обычный move.w (sp)+,d0 - не расширяет. |
| DrMefistO:
Еще вопрос: --- Код: ---cmp.w #$100,d3 --- Конец кода --- В каких случаях будет устанавливаться Carry Flag? |
| r57shell:
--- Цитата: DrMefistO от 13 Сентябрь 2012, 16:09:50 ---Еще вопрос: --- Код: ---cmp.w #$100,d3 --- Конец кода --- В каких случаях будет устанавливаться Carry Flag? --- Конец цитаты --- Во всех которые я встречал ассемблерах cmp двух операндов работает как cmp (op1-op2) только порядок может быть разным. а carry flag это когда из меньшего вычли большее. более подробно допустим op1 = $23, op2 = $34 тогда будет мысленно приписываем 1 за старшим битом того, из чего вычитают $10023 - $34 = $FFEF единица пропала, значит carry то есть "заняли"/"не хватило" наоборот $10034 - $23 = $10011 значит нету carry, не заняли. аналогично overflow это когда после складывания двух, стало переполнение. а так, смотри мануал, мне лень :( |
| DrMefistO:
Спасибо) |
| r57shell:
--- Цитата ---Scc, FScc <ea> 8 If Condition True, Then 1's →Destination; Else 0's →Destination --- Конец цитаты --- такчто код не правильный. |
| DrMefistO:
--- Цитата: r57shell ---такчто код не правильный. --- Конец цитаты --- Эмм, не понял. В смысле "не правильный"? Который? |
| GManiac:
--- Цитата: Ti_ от 13 Сентябрь 2012, 13:31:52 ---Scc прописывание значения byte -$FF --- Конец цитаты --- --- Цитата ---Вроде может если от -$7FFF до -$FFFF . --- Конец цитаты --- Нет таких чисел :) Точнее, это не то, что ты имеешь в виду, а отрицательные числа -255 и др., записанные в прямом коде. Смотря на значения регистров, надо всегда думать об обратном коде. http://ru.wikipedia.org/wiki/Прямой_код_(представление_числа) http://ru.wikipedia.org/wiki/Обратный_код http://ru.wikipedia.org/wiki/Дополнительный_код_(представление_числа) А кому хочется мазохизма, читайте книжку Садо Самофалова "Прикладная теория цифровых автоматов." :lol: Там разобраны все нюансы. Сами по себе значения в регистрах ничего о себе не говорят. Какое число они реально представляют, зависит от инструкции, она выбирает размер и вид записи числа (прямой/обратный) - то, что мы называем знаковой/беззнаковой операцией. Операции сложения и вычитания у 68k всегда беззнаковые, но это не значит, что они не работают с отрицательными числами, просто результат (в регистре, а не для человека) в обоих представлениях одинаковый. А уж как его интерпретировать - дело другое. И обработка переполнения и переноса (флаги C, V) на совести программиста. Основных проблем две: либо число не влезает в разрядность, либо в результате получается число другого знака - опять же из-за нехватки разрядов. Примеры, включая проблемные. Пишу сходу, поэтому могу ошибаться. 1. $0064 + $FFFE = $0062 1) $FFFE значит -2, и всё нормально. 2) $FFFE - некое большое число 65534, из-за чего в результате сложения мы должны получить 65634 ($10062), которое не влезает в тип word. Вот тут скорей всего $FFFE означает на самом деле -2, а такие исходные данные мы можем получить, например, когда к некой координате #$0064 прибавляется отрицательный шаг -2. Скажем, герой сделал шажок влево. То, что содержимое регистра не говорит о его знаке, справедливо и для языков высокого уровня. Пример на паскале: --- Код: ---var a, b : word; c, d, e : smallint; begin a := 100; b := $FFFE; c := b; { Фактически, ячейка c содержит то же самое, что b, это можно посмотреть в памяти } d := a + b; e := a + c; writeln( b ); writeln( c ); writeln( d ); writeln( e ); end. --- Конец кода --- 2. $8001 + $8001 = $0002. -32766 + (-32766) = 2 Получается число неправильного знака. Но как правило, исходя из примера 1, лучше считать все числа знаковыми, особенно если они word. Число $FF почти всегда означает именно -1, часто используется в качестве флага для операций TST. Оно так популярно, потому что его также легко установить: MOVEQ, Scc. В теме "Геймдев для 68k" я объяснял назначение команд Scc, не помню, писал ли я там, почему в качестве флага применяется именно -1, а не +1. Напомню про сами Scc: с их помощью можно вычислять сложные логические выражения без использования прыжков. Например, конструкцию на паскале --- Код: ---isEqua := a = b; --- Конец кода --- можно записать так: --- Код: ---TST.w a, b SEQ isEqua --- Конец кода --- А как быть, если выражение сложнее, чем одна операция сравнения? Тут и приходит на помощь число -1 = $FF и битовые операции. Как вы знаете, в C/C++ можно мешать логические и битовые операции, они даже обозначаются схоже. Вообще, изначально, на уровне одного бита логические и битовые операции работают идентично. Всё бы ничего, но в числах больше одного бита. В сях этот вопрос решили так: число 0 считается равным ЛОЖЬ, любое другое - ИСТИНА. И наоборот, ЛОЖЬ считается равной 0. Хорошо, а какое число си считает равным ИСТИНЕ по умолчанию, т.е. когда логическое значение приводится к числовому? В книжках по сях пишут, что +1, но я не проверял. А в M68k используется -1, что я считаю более правильным. Почему? Потому что набор чисел 0 и -1 всегда ведёт себя одинаково что в логических операциях, что в арифметических, а набор 0 и +1 - нет. Это объясняется просто: у числа 0 все биты одинаковые, у -1 - тоже. А как я писал выше, на битовом уровне оба набора операций работают одинаково. У числа же +1 только младший бит 1, остальные - нули, т.е. биты различаются. Реально проблема вылезает только с операцией NOT - отрицание условия / битовая инверсия. not 0 = -1 (not 00000000b = 11111111b) not -1 = 0 (not 11111111b = 00000000) not +1 = -2 (not 00000001b = 11111110b) Вот тут сишная логика даёт сбой: число -2 не входит в набор (0; -1) и его уже нельзя использовать в битовых операциях для вычисления логических выражений. --- Цитата ---Эмм, не понял. В смысле "не правильный"? Который? --- Конец цитаты --- Он про код на паскале, там 0 не учтён. Самый простой код выглядит так. --- Код: ---if d0 < 0 then d0 := -1 else d0 := 0; --- Конец кода --- Проще, но не факт, что правильный: --- Код: ---d0 := byte( d0 < 0 ); --- Конец кода --- Тут нужно приведение, потому что в паскале нельзя мешать boolean и числа. На сях можно. Тут, вероятней всего, -1 / 0 будет использоваться как флаг для дальнейшних CMP, а не для "вычисления сложных логических выражений с использованием битовых операций", т.к. я такого ни разу не видел :) Поэтому непонятно, зачем для CMP приводить отрицательное/положительное число к виду -1 / 0, когда можно оставить просто число и проверять после CMP другие флаги:) По поводу CMP, флагов и сравнения чисел по-человечески (сам всегда путаюсь) глянь эту доку, самый конец: http://www.zophar.net/fileuploads/2/10541whpzw/68000insset.txt --- Цитата --- Condition Codes set after CMP D0,D1 Instruction. Relationship Unsigned Signed ------------ -------- ------ D1 < D0 CS - Carry Bit Set LT - Less Than D1 <= D0 LS - Lower or Same LE - Less than or Equal D1 = D0 EQ - Equal (Z-bit Set) EQ - Equal (Z-bit Set) D1 != D0 NE - Not Equal (Z-bit Clear) NE - Not Equal (Z-bit Clear) D1 > D0 HI - HIgher than GT - Greater Than D1 >= D0 CC - Carry Bit Clear GE - Greater than or Equal PL - PLus (N-bit Clear) MI - Minus (N-bit Set) VC - V-bit Clear (No Overflow) VS - V-bit Set (Overflow) RA - BRanch Always --- Конец цитаты --- |
| r57shell:
GManiac, нет, я не это имел ввиду. Изначально был другой вопрос. Код на asm и его интерпретация на языке высокого уровня. короче не $FF и не -1, а 1 должно быть, судя по доке M68k. Цитата оттуда в предыдущем моём посте. И ещё вопрос: GManiac - ты это сейчас написал? или откуда-то скопипастил, ато надоже было столько на флудить o_0. --- Код: ---ROM:00005AF6 tst.w d0 ROM:00005AF8 slt d0 --- Конец кода --- на C++ будет так --- Код: ---short d0; d0 = (d0<0?1:0); --- Конец кода --- или int версия --- Код: ---int d0; d0 = (d0&0x8000?1:0); --- Конец кода --- или проще --- Код: ---d0 >>= 15; --- Конец кода --- int версии подразумевают что значение от 0 до $FFFF. |
| Ti_:
--- Цитата: r57shell от 13 Сентябрь 2012, 17:46:56 ---короче не $FF и не -1, а 1 должно быть, судя по доке M68k. Цитата оттуда в предыдущем моём посте. --- Конец цитаты --- Ты проверь вначале - s** прописывают либо 0 либо $FF. Добавлено позже: --- Цитата: DrMefistO от 13 Сентябрь 2012, 16:09:50 ---Еще вопрос: --- Код: ---cmp.w #$100,d3 --- Конец кода --- В каких случаях будет устанавливаться Carry Flag? --- Конец цитаты --- Апельсин слишком запутал всё. Получится всего два диапозона - от 0 до $100 и от $100 до $FFFF. Только надо проверить где включительно а где нет. BGE=BCC (то есть тоже что и больше или равно - но для всего диапозона без знака), BLT=BCS. Вроде так. А насчет других процессоров в не-моторолских процах обратный порядок байт и операций, поэтому там BCC BCS наоборот везде перепутаны. (точнее там разный порядок что с чем сравнивают op1 и op2 - то что он написал про порядок) |
| r57shell:
добавлю ещё на счёт прямого кода. В прямом коде старший бит означает знак, остальное как с положительными то есть $01 = 00000001b = 1 $81 = 10000001b = -1 но тут есть попа $00 = 00000000 = +0 $80 = 10000000 = -0 :D вроде итак всё пучком, зачем обратный код? да чтобы схемотехника была проще в обратном чтобы получить -1 можно просто вычесть из нуля 1 по простым принципам вычитания столбиком :) 00000000b = 0 00000001b = 1 вычтем и займём получим (хоть и занимать не откуда) 11111111b = $FF это и есть -1 в этом и вся прелесть если к -1 прибавить 1 снова прелесть (просто лишний 1 некуда девать "overflow") 11111111b = $FF 00000001b = $1 получится 00000000b = 0 как должно быть так что, в обратном коде, от -$7E до + $7E всё пучком, просто будут какие-то переполнения, а результат как и ожидалось. А на ошибки, при сложении $7F+$1=$80=-(дофига) просто забивают, т.к. нет такого значения байтового. и по этому схемотехника просто сложение столбиком, без учёта знаков. зато с точки зрения беззнакового, $7F+1 всё корректно :). То есть и знаковое и беззнаковое тут одинакого. вот. кстати, что в прямом коде что в обратном, старший бит означает знак. если 1 то отрицательное. |
| DrMefistO:
Вот что дает отладчик: Если в d0 имеется число 3C46, к примеру, то после SLT в d0 будет $3CFF, а если $8001, то в d0 будет $8000. Как это все учитывать? И приведите пример ситуации с нулем, и какой результат будет. |
| Навигация |
| Главная страница сообщений |
| Следующая страница |