Assembly 火星MIPS模拟器是大端还是小端

Assembly 火星MIPS模拟器是大端还是小端,assembly,mips,endianness,mars-simulator,Assembly,Mips,Endianness,Mars Simulator,我必须确定火星模拟器是大的还是小的endian作为家庭作业,起初这看起来很简单,但我有一些问题 首先,我尝试在内存中存储4个字节。字节0,0,0,1在内存中显示为0x01000000,因此,以相反的顺序,这似乎表明模拟器是little endian,但是,当我将4个字节作为整数加载到寄存器中时,寄存器中再次显示的是0x01000000,据我所知,如果是little endian,将加载的是0x00000001 另外,当使用.word 1存储4个字节时,存储的是0x00000001,这次没有反转的

我必须确定火星模拟器是大的还是小的endian作为家庭作业,起初这看起来很简单,但我有一些问题

首先,我尝试在内存中存储4个字节。字节0,0,0,1在内存中显示为0x01000000,因此,以相反的顺序,这似乎表明模拟器是little endian,但是,当我将4个字节作为整数加载到寄存器中时,寄存器中再次显示的是0x01000000,据我所知,如果是little endian,将加载的是0x00000001

另外,当使用.word 1存储4个字节时,存储的是0x00000001,这次没有反转的字节

我想知道模拟器是大端还是小端,对这种行为的解释来自网站:


正如你所看到的,这是小endian,在你的问题中有好几个层次,所以我试着一个一个地解决它们

机器: 这台机器的内存可按字节寻址。第一个字节有地址0,第二个字节有地址1,等等。。。每当我在这个答案中写关于内存内容的内容时,我都会使用以下格式:
01 02 0E 0F 10…
,使用十六进制值和字节之间的空格,地址从起始地址一直到结束地址。也就是说,如果此内容从地址0x800000开始,则内存将为(所有十六进制):

到目前为止,无论目标MIPS平台是小端还是大端,只要涉及字节大小的内存,字节顺序都是“正常”的

如果将字节从地址
0x800000
加载到
t0
(使用
lb
指令),
t0
将等于值
1

如果将单词从地址
0x800000
加载到
t0
(使用
lw
指令),则最终将播放endianness

little endian机器上,
t0
将等于值
0x0F0E0201
,字的第一个字节(内存中)为2560(最低功耗),第二个字节为2561。。。最后一个是2563美元

big-endian机器上,
t0
将等于值
0x01020E0F
,字的第一个字节(内存中)为2563,第二个字节为2562。。。最后一个是2560美元

(,这个神奇的数字来自“一个字节是8位”,一位可以包含两个值(0或1),一个字节有8位,所以一个字节可以包含28个不同的值)

在这两种情况下,CPU都将从内存中读取相同的四个字节(地址0x800000到0x800003),但endianness定义了它们作为字值的最后32位出现的顺序

t0
由CPU芯片上的32位物理形成,它没有地址。当您想在CPU指令中对其进行寻址时(即,使用存储在
t0
中的值),您可以将其编码为
$8
寄存器(
$8
具有
$t0
别名,以便在您的汇编程序中使用,因此我使用的是
t0
别名)

endianness不适用于寄存器的这32位,它们已经是32位b0-b31,一旦值
0x0F0E0201
加载,这32位被设置为
0000 1111 0000 1110…
(我正在从b31的顶部写到b0的底部,以理解左/右移位指令,并使其作为人类格式化的二进制数工作),没有必要考虑寄存器的端性或位在芯片上存储的物理顺序,只需将其视为完整的32位值,在算术指令中,它就可以这样工作

当将带有
lb
的字节值加载到寄存器中时,它进入b0-b7位,其中b8-b31包含b7的副本(符号将有符号8位值扩展为有符号32位值)

当将寄存器的值存储到内存中时,endianness同样适用,即将
0x11223344
存储到内存中会将单个字节设置为
44 33 22 11

汇编程序(源代码和编译) 为其目标平台配置良好的汇编器将对程序员隐藏endianness,以方便使用字值

因此,当您定义内存值时,如:

myPreciousValue .word 0x11223344
汇编程序将解析文本(您的源代码是文本(!),即一个字符是一个字节值-在ASCII编码中,如果您在UTF8文本编辑器中写入源代码并使用非ASCII字符,则它们可能跨多个字节进行编码,ASCII可打印字符在ASCII和UTF8中具有相同的编码,并且仅占用一个字节)“0x11223344”(10字节
30 78 31 32 32 33 34
),从中计算32位字值
0x11223344
,然后将目标平台端性应用于该值,以生成四个字节的机器代码,或者:

44 33 22 11           # little-endian target
或:

然后在代码中使用
lw
指令将
myPreciousValue
从内存加载到寄存器时,寄存器将包含预期的字值
0x11223344
(只要你没有混淆你的汇编器配置和使用错误的端号,就不可能在MARS/SPIM中发生,因为它在所有东西(VM、汇编器、调试器)中只支持很少的端号配置)

因此,程序员不必每次在源代码的某个地方写入32位值时都考虑endianness,汇编程序将解析并将其处理为字节值的目标变量

如果程序员想在内存中定义四个字节
01 02 03 04
,她可以“聪明”地为little endian目标平台使用
.word 0x0403001
,但这混淆了最初的意图,因此我建议在这种情况下使用
。字节1、2、3、4
,因为程序员的意图是定义字节,而不是定义单词。

myPreciousValue .word 0x11223344
44 33 22 11           # little-endian target
11 22 33 44           # big-endian target
0x800000: 31 32 33 34 41 42 43 44 | 1234ABCD
0x800000: 34333231 44434241
.data

checkEndianness: .word 0    # temporary memory for function
    # can be avoided by using stack memory instead (in function)

.text

main:
    jal  IsLittleEndian
    # ... do something with v0 value ...
    ... exit (TODO by reader)

# --- functions ---

# returns (in v0) 0 for big-endian machine, and 1 for little-endian
IsLittleEndian:
    # set value of register to 1
    li $v0,1
    # store the word value 1 into memory (4 bytes written)
    sw $v0,(checkEndianness)
      # memory contains "01 00 00 00" on little-endian machine
      #              or "00 00 00 01" on big-endian machine
    # load only the first byte back
    lb $v0,(checkEndianness)
    jr $ra