我是一名硕士生,目前正在做我的夏季最终项目,该项目是关于设计带有FPU的MIPS处理器并在FPGA中实现。
我要实施的说明取决于我使用的交叉编译器。所以,从硬件设计师的角度来看,我通过首先查看可以从编译器生成的指令启动项目。
对于整数设计(主要核心设计),我写了一些C代码,例如,一个简单的代码:
touchpad='SynPS/2 Synaptics TouchPad id=14 [slave pointer (2)]'
sed -r 's~.*TouchPad id=([0-9]+).*~\1~' <<< "$touchpad"
14
一个简单的补充,编译器提供汇编代码:(我刚刚在main发布了汇编代码,因为我没打算在我的MIPS上运行操作系统)
int main ()
{
int a,b,c;
a=1;
b=2;
c=a+2;
}
我喜欢理解汇编代码,这可以帮助我更多地理解MIPS架构,并且根据指令顺序,我可以基于编译器设计危险检测单元。
我们可以从这4条指令中看到:
00400168 <main>:
400168: 27bdffe8 addiu sp,sp,-24
40016c: afbe0010 sw s8,16(sp)
400170: 03a0f021 move s8,sp
400174: 24020001 li v0,1
400178: afc20008 sw v0,8(s8)
40017c: 24020002 li v0,2
400180: afc20004 sw v0,4(s8)
400184: 8fc20008 lw v0,8(s8)
400188: 00000000 nop
40018c: 20420002 addi v0,v0,2
400190: afc20000 sw v0,0(s8)
400194: 03c0e821 move sp,s8
400198: 8fbe0010 lw s8,16(sp)
40019c: 27bd0018 addiu sp,sp,24
4001a0: 03e00008 jr ra
编译器将1,2加载到变量a,b。 对于整数汇编代码,我可以理解没有问题。
好的,让我们去浮点单位,就像我一样,我写了一个非常相似的C:
浮点测试C代码
400174: 24020001 li v0,1
400178: afc20008 sw v0,8(s8)
40017c: 24020002 li v0,2
400180: afc20004 sw v0,4(s8)
现在汇编代码差异很大:
void main ()
{
float a,b,c;
a=1;
b=2;
c=a+b;
}
不喜欢以前的代码,这6条指令看起来像程序从数据存储器加载变量的值而不是使用指令li :
00400168 <main>:
400168: 27bdffe8 addiu sp,sp,-24
40016c: afbe0010 sw s8,16(sp)
400170: 03a0f021 move s8,sp
400174: c7808004 lwc1 $f0,-32764(gp)
400178: 00000000 nop
40017c: e7c00008 swc1 $f0,8(s8)
400180: c7808008 lwc1 $f0,-32760(gp)
400184: 00000000 nop
400188: e7c00004 swc1 $f0,4(s8)
40018c: c7c20008 lwc1 $f2,8(s8)
400190: c7c00004 lwc1 $f0,4(s8)
400194: 00000000 nop
400198: 46001000 add.s $f0,$f2,$f0
40019c: e7c00000 swc1 $f0,0(s8)
4001a0: 03c0e821 move sp,s8
4001a4: 8fbe0010 lw s8,16(sp)
4001a8: 27bd0018 addiu sp,sp,24
4001ac: 03e00008 jr ra
4001b0: 00000000 nop
出现了问题,我无法弄清楚-32764(gp)和f0,-32760(gp)中存储的值是什么,因为没有任何SW指令尝试将数据存储到那些地址
以下是编译器生成的完整汇编代码:
400174: c7808004 lwc1 $f0,-32764(gp)
400178: 00000000 nop
40017c: e7c00008 swc1 $f0,8(s8)
400180: c7808008 lwc1 $f0,-32760(gp)
400184: 00000000 nop
400188: e7c00004 swc1 $f0,4(s8)
我不擅长MIPS汇编,有人可以解释一下浮点变量&#39;值1和2?
答案 0 :(得分:4)
ELF可执行文件可以有一个或多个部分填充程序使用的静态数据(字符串,浮点数,数字等)。 这些部分由加载程序与程序的其余部分一起加载到内存中,从而避免混合代码和数据并减少代码大小。
对于MIPS系统上的ELF,你应该参考this哪里有这个漂亮的图片:
正如您所看到的,$gp
用于解决 .sdata 和 .sbss 部分,其中最初的 s 代表对于小。
所有这些努力都是为了最小化代码大小,因为使用$gp
编译器可以生成16位偏移(相对于通常使用的32位偏移)。
由于偏移已签名,$gp
位于由 .sdata + .sbss 形成的(最多)64 KiB区域的中间。
您的浮点值不会直接在指令中编码,因为FP指令does not takes immediates,而是将它们保存到只读部分并从那里加载。
为什么最后你关心这个?
如果您的目标是设计MIPS ISA的实现,只需选择特定的ISA(MIPS32 I?MIPS32 IV?MIPS 64?),获取文档,全面了解并实现微体系结构。
如果一条指令是根据您选择的ISA的有效指令,那么您的实现必须能够执行它,不要担心编译器正在做什么,它们是否已经长大,他们可以自己照顾他们自己如果你执行的代码坏了,谁在乎呢?只要它有效。
这些将对您有所帮助:
MIPS32™ Architecture For Programmers Volume I: Introduction to the MIPS32™ Architecture MIPS32™ Architecture For Programmers Volume II: The MIPS32™ Instruction Set