MIPS - Как конвертировать набор целых чисел в плавающие с одинарной точностью

Мне действительно трудно понять, как подойти к этой проблеме. Я понял, что хочу взять двоичное представление как целого числа, так и дроби, объединить их для мантиссы и присвоить знаковый бит началу, но я не знаю, как на самом деле реализовать его в MIPS.

Может кто-нибудь помочь мне хотя бы начать?

Предположим, что ваше оборудование MIPS не имеет регистров с плавающей точкой и ALU с плавающей точкой. Если вы хотите выполнить сложение с плавающей запятой, вам придется использовать целочисленные инструкции MIPS, которые используют целочисленные регистры ($0 - $31) и целочисленный ALU, чтобы выполнить работу. В этом вопросе о назначении вы напишите код MIPS, используя только целочисленные инструкции и только целочисленные регистры, чтобы реализовать процедуру добавления двух чисел с плавающей запятой и написать основную функцию для вызова процедуры.

  1. Напишите процедуру MIPS toFloat, чтобы поместить число с плавающей запятой в формат IEEE с одинарной точностью. Процедура принимает три целых числа в качестве входных данных: $a0, $a1, $a2, которые представляют число с плавающей запятой следующим образом: если $ a0 содержит 0, число с плавающей запятой является положительным, иначе, если $ a0 содержит 1, Число с плавающей точкой отрицательно. Число, хранящееся в регистре $ a1, является целой частью числа с плавающей запятой, а число, сохраненное в регистре $ a2, является дробной частью числа с плавающей запятой. Например, чтобы представить число с плавающей запятой -5.25, три входных регистра должны содержать эти числа: $a0 = 1, $a1 = 5 и $a2 = 25. Для дробной части вы можете использовать div rs rt Инструкция поделить 25 на 100. Фракция будет сохранена в регистре HI, и вы можете использовать инструкцию mfhi для ее получения. Процедура вернет v0, который содержит шаблон одинарной точности IEEE, соответствующий числу с плавающей запятой, представленному тремя входными числами. Получив эту процедуру, вы можете использовать ее для преобразования входных чисел 2.5 и 7.5 в их формат IEEE с одинарной точностью.

  2. Напишите процедуру MIPS printFloat для печати числа в формате IEEE с одинарной точностью. Ввод процедуры осуществляется в $ a0, который является числом в формате IEEE с одинарной точностью. Процедура просто распечатает битовый шаблон, хранящийся в $a0. Вы можете использовать цикл для печати каждого бита. Если у вас есть эта процедура, вы можете использовать ее для печати входных чисел 2.5 и 7.5 в их формате с плавающей запятой.

  3. Напишите программу MIPS для реализации основной функции для вызова ваших процедур. В этой программе вам позвонят

    toFloat(0, 2, 5) для генерации формата с плавающей точкой для 2.5;

    toFloat (0, 7, 5) для генерации формата с плавающей запятой для 7.5;

    printFloat для печати 2.5

    printFloat для печати 7.5

Вот код, который у меня есть:

http://s7.postimg.org/v39ufikaj/code.png

1 ответ

Хорошо, первый шаг (как отмечено в комментариях) - провести некоторое время с конвертером, который показывает биты, как показано здесь: двоичный конвертер с плавающей запятой.

Затем легко взять $a0 и сбросить бит 0 в бит 1 нашего результата. Что-то вроде:

add $v0, $zero, $zero # initialize our result
sll $t0, $a0, 31 # shift the lsb to the msb
or $v0, $v0, $t0 # set the sign bit in the result

Но теперь мы должны заняться математикой. Я надеялся, что $a1 будет частью целого числа, а $a2 будет двоичной дробной частью. Но это не так... говорят, что $a1 - это целое число (все еще целое число в двоичном виде), но $a2, по сути, центы. (Если 25/100 = 0,25 десятичного числа, то $a2 содержит центы.)

Вот где я запутался, сам. В инструкциях написано "используйте команду div rs rt, чтобы разделить 25 на 100. Дробь будет сохранена в регистре HI". Но когда я читаю что div делает ( MIPS Instruction Reference), он говорит, что ставит частное в $LO, а остаток в $HI. Таким образом, деление 25 на 100 даст вам... 25. Это хороший способ отбросить сумму больше 100, но это не приводит нас к двоичному дробному представлению числа.

Фактически, я просто провел целый класс плюс обед, пытаясь найти элегантный способ взять число от 0 до 99, разделить его на 100 и преобразовать результат в двоичный файл без использования FPU. Я подойду коротко. Так что я позволю вам спросить профессора об этой части.

Но как только мы получим целую часть числа в $a1 и строку из 1 и 0, представляющую дробную часть (давайте поместим это в $s2), нам просто нужно ее нормализовать. У нас есть номер в $a1, $s2 и нам нужно, чтобы он был в следующем формате:

1.nnnnnnn

... где мы начинаем с 1, а затем дробная часть состоит из множества двоичных цифр.

Вот некоторый псевдокод, который может работать.

  • Сдвигайте $a1 влево, пока msb не станет равным "1". Хранить количество смен в $ t0. (Примечание: предполагается, что целая часть не равна нулю)
  • (31 - $ t0) дает вам показатель степени. Отрегулируйте его с помощью смещения и добавьте в биты 30-23 результата с плавающей запятой.
  • $ t0 также говорит вам, сколько места у вас есть для дробных битов. Сдвиньте $ s2 на соответствующую величину (которая зависит от того, как она закодирована), и or это так, что он заполняет младшие биты $a1
  • Shift $a1 оставил еще один бит, потому что начальная "1" отбрасывается в IEEE FP
  • Сложить верхние 23 бита $a1 в биты 22-0 результата с плавающей запятой

Давайте посмотрим, работает ли это на примере. $a1 содержит целую часть 0x0000C000, а $ s2 каким-то образом загружен с 0,75 (1 x 2^-1 + 1 x 2^-2)

$a1: 0000 0000 0000 0000 1100 0000 0000 0000 
$s2: 1100 0000 0000 0000 0000 0000 0000 0000

Я должен сдвинуть $a1 16 раз:

$a1: 1100 0000 0000 0000 0000 0000 0000 0000 

Это должно дать мне показатель степени 31 - 16 = 15. Добавьте смещение 127, и я получу 142 (0x8E). Это идет в разделе экспоненты.

Мне нужно сдвинуть $ s2 вправо на ту же сумму (16):

$s2: 0000 0000 0000 0000 1100 0000 0000 0000

or те вместе:

$a1:  1100 0000 0000 0000 1100 0000 0000 0000

Визуализируйте это с десятичной точкой:

original:  1100 0000 0000 0000.1100 0000 0000 0000
normaliz: 1.100 0000 0000 0000 1100 0000 0000 0000

Поскольку мы опускаем подразумеваемое "1" слева от десятичной запятой, смещаем его и получаем:

$a1:  100 0000 0000 0000 1100 0000 0000 0000 0

Возьми 23 бита этого. Так что, если я правильно понял, приведенный выше конвертер должен сказать, что 49152.75 сохраняет в IEEE FP как:

01000111 01000000 00000000 11000000

Знак = 0

Экспонент = 10001110 (0x8E)

Мантисса = 1000 0000 0000 0001 1000 000

(Теперь попробуйте представить мое удивление, что это действительно сработало!)

Другие вопросы по тегам