Разработка и ромхакинг > Ромхакинг и программирование
Нужна помощь по командам 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.

Как это все учитывать? И приведите пример ситуации с нулем, и какой результат будет.
Навигация
Главная страница сообщений
Следующая страница

Перейти к полной версии