Многоточная арифметика на MIPS
Я просто пытаюсь реализовать мультиточную арифметику на родном MIPS. Предположим, что одно 64-разрядное целое число находится в регистрах $12 и $13, а другое - в регистрах $14 и $15. Сумма должна быть внесена в регистры $10 и $11. Наиболее значимое слово из 64-разрядного целого числа находится в регистрах с четными номерами, а наименее значимое слово - в регистрах с нечетными номерами. В интернете сказано, что это самая короткая реализация.
addu $11, $13, $15 # add least significant word
sltu $10, $11, $15 # set carry-in bit
addu $10, $10, $12 # add in first most significant word
addu $10, $10, $14 # add in second most significant word
Я просто хочу проверить, правильно ли я понимаю. Sltu проверяет, является ли сумма двух наименее значимых слов меньше или равна одному из операндов. Если это так, то когда произошел перенос, так ли это?
Чтобы проверить, произошел ли перенос при добавлении двух наиболее значимых слов, и сохранить результат в $9, я должен сделать:
sltu $9, $10, $12 # set carry-in bit
Есть ли в этом смысл?
1 ответ
Sltu проверяет, является ли сумма двух наименее значимых слов меньше или равна одному из операндов.
Не совсем: это устанавливает $10
1, если сумма двух наименее значимых слов строго меньше, чем один из операндов (рассматривается как 32-разрядные значения без знака); и 0, если сумма равна или больше, чем этот операнд.
Если это так, то когда произошел перенос, так ли это?
Да.
Рассмотрим, что может произойти при добавлении различных возможных значений b к некоторому конкретному значению a (где все является 32-разрядным значением без знака):
- Если переполнение не произошло, мы должны иметь <= sum <= 0xFFFFFFFF, поэтому 0 <= b <= (0xFFFFFFFF - a).
- Остальные случаи для b вызывают переполнение; фактическая сумма в этих случаях должна быть 0x100000000 <= sum <= a + 0xFFFFFFFF, что при усечении до 32 битов дает 0 <= sum <= a - 1.
Чтобы проверить, произошел ли перенос при добавлении двух наиболее значимых слов, и сохранить результат в $9, я должен сделать:
sltu $9, $10, $12 # set carry-in bit
Не совсем.
Проблема в том, что вы добавляете два 32-битных значения и, возможно, перенос из суммы наименее значимых слов. Например, рассмотрим случай, когда есть перенос, и оба наиболее значимых слова - 0xFFFFFFFF: сумма будет 1+ 0xFFFFFFFF + 0xFFFFFFFF = 0xFFFFFFFF, и поэтому перенос не будет установлен (но так и должно быть).
Одним из способов справиться с этим будет проверка переноса после добавления $12
в $10
и проверьте еще раз после добавления $11
на эту сумму. Только одна из этих сумм может произвести перенос ($12 + $10
переполняется только когда $12
0xFFFFFFFF, потому что $10
0 или 1; и в этом случае сумма равна 0, поэтому вторая сумма также не может переполниться).
Так что это может (отказ от ответственности: уже поздно, и это не проверено) сделать свое дело:
addu $11, $13, $15
sltu $10, $11, $15 # carry from low word
addu $10, $10, $12
sltu $9, $10, $12 # possible carry from high word (1)
addu $10, $10, $14
sltu $8, $10, $14 # possible carry from high word (2)
or $9, $8, $9 # carry in result if either (1) or (2) were true (can't both be true at once)