Вопрос или проблема
Что именно делает инструкция lb?
У меня скоро экзамен, и одна из практических задач звучала так:
Предположим, что
$t0
содержит значение0x12121212
, а$t1
содержит
адрес0x1000000
.Предположим, что данные в памяти, начиная с адреса
0x1000000
, составляют:
88 77 66 55
.Каково будет значение
$t0
после выполнения следующего кода:lb $t0, 0($t1)
a)
0x00000088
b)0x88121212
c)0xffffff88
d)0x12121288
Ответ, который я дал, был a
, потому что байт, который команда lb
прочитает (по моему пониманию того, что делает эта команда), равен 88. Значение 88 затем будет сохранено в $t0
, и таким образом значение станет 0x00000088
. Но ответ был указан как c
. Мне кажется, у меня есть фундаментальное недопонимание того, как работает lb
– может кто-то объяснить, почему ответ c
?
Ответ будет c) 0xffffff88
. Команда lb
делает знаковое расширение байта до 32-битного значения. То есть старший бит (msb) копируется в верхние 24 бита.
0x88 == 0b10001000, т.е. старший бит равен 1. Поэтому верхние 24 бита будут 0b111111111111111111111111 == 0xffffff.
Команда lb
загружает байт из памяти и делает знаковое расширение
до размера регистра. Команда lbu
делает то же самое без знакового расширения (без знака).
http://en.wikipedia.org/wiki/MIPS_architecture#Integer
Большинство компьютеров, включая MIPS, используют двоичное представление со знаком для представления знаковых значений, хотя существуют другие способы кодирования знака, числа с плавающей точкой обычно представляются в формате IEEE 754, который использует представление со знаком. Знаковое целое число может быть представлено в любом количестве бит, например:
char
в C занимает 8 бит и может представлять значения от -128 до +127short
в C занимает 16 бит и может представлять значения от -32768 до +32767- и т.д.
В двоичном представлении со знаком самый старший бит может использоваться для определения знака числа, '1'
означает, что число отрицательное, а '0'
означает, что число положительное.
Число 0x88, когда интерпретируется как 8-битное двоичное число со знаком, является отрицательным равным 0x78 или -120 в десятичной системе. При представлении в 32 бита в двоичном представлении со знаком это будет 0xFFFFFF88. Существуют несколько способов запомнить, как вычислить двоичное дополнение числа:
- взять дополнительный код числа (инвертировать каждый бит) и прибавить ‘1’, или
- идти от младшего бита к старшему (справа налево), пропустив каждый ‘0’ и первый ‘1’, который вы встретите, инвертировать каждый бит после этого
Чтобы сделать знаковое расширение с 8 бит до 32 бит, просто посмотрите на самый старший бит (бит 7) и скопируйте этот бит в биты с 8 до 31… Это вытекает из определения двоичного дополнения.
Ответ или решение
Инструкция lb
(load byte) в архитектуре MIPS загружает один байт памяти и расширяет его до 32 бит с учетом знака. Давайте разберемся, как это работает на конкретном примере.
Условия задачи
Предположим, что:
- Регистр
$t0
изначально содержит значение0x12121212
. - Регистр
$t1
содержит адрес0x1000000
. - В памяти, начиная с адреса
0x1000000
, расположены данные:88 77 66 55
.
Что делает инструкция lb $t0, 0($t1)
?
-
Чтение байта из памяти:
Инструкцияlb
обращается по адресу, указанному в регистре$t1
(в данном случае,0x1000000
), и считывает один байт. Первым байтом по этому адресу является0x88
. -
Расширение знака:
После того как мы прочитали байт0x88
, этот байт интерпретируется как 8-битное знаковое число. В двоичном представлении0x88
— это10001000
. В этом представлении старший бит (бит 7) равен1
, что указывает на то, что число отрицательное в системе представления со знаком (двойное дополнение).В двоичном виде:
0x88
=10001000
(в 8 битах)- Как знаковое число, оно эквивалентно
-120
в десятичной системе.
- Расчет 32-битного представления:
Чтобы представить0x88
как 32-битное число с учетом знака, необходимо заполнить старшие 24 бита значением старшего бита (бит 7). Так как старший бит равен1
, мы заполняем старшие 24 бита единицами:- Результат:
0xFFFFFF88
.
- Результат:
Ответ
Таким образом, после выполнения инструкции lb $t0, 0($t1)
, значение в регистре $t0
станет 0xFFFFFF88
.
Следовательно, правильный ответ на вопрос, что будет содержать регистр $t0
после выполнения этой инструкции, — это вариант c:
- c)
0xffffff88
.
Эта информация должна помочь вам лучше понять работу инструкции lb
и расширение знака в MIPS. Удачи на экзамене!