• 3
  • 11月

openrisc,或者说mips吧,跳转指令会有一个延迟槽。

首先,Hanny可能先需要解释一下什么是延迟槽。我们知道,CPU指令在执行跳转指令时,一般是会清空流水线的。这样,就会造成几个指令周期的浪费。具体浪费周期数取决于流水线的级数。

而延迟槽的作用呢,则是在执行完跳转指令,并执行跳转指令的下一条指令后,才会真正地跳转至目标PC。因此,延迟槽在一定程度上,能够提高CPU的效率。

有的时候,可能不想去利用延迟槽,在GCC的编译选项中增加

-fno-delayed-branch

这样,在编译过程中的跳转,都会在延迟槽中填入nop指令。缺点就是有点浪费程序空间了。

  • 25
  • 11月

费了好大的劲,终于知道gp寄存器的用法了。

首先说说gp寄存器出现的原因吧,由于RISC体系的CPU,每条指令都是32Bit,而地址总线也是32Bit,这样,就不可能通过一条指令来实现Memory的访问。

MIPS中,访问Memory的指令格式为:

lw r1, offset(r2)

其中,offset为16Bit,也就是说,最多能访问以r2为基地址,前后32K的空间。

于是这个时候,gp就闪亮登场了。

我们知道,GCC在编译过程,会将变量分别放在data,bss,common等段。而编译mips程序时,会将小变量放入sdata,sbss,scommon等段。这个大小由编译选项-G来决定。-G0则表示不使用小数据段。默认是-G8,表示小于或等于8 byte的数据将放入小变量区。

这样的话,在上电时给gp初始化一个值,那么,所有小变量区的变量就可以通过

lw r1, offset(gp)

来访问了。

那么,GCC怎么知道gp初始化的值呢?只要在link文件中添加_gp符号,连接器就会认为这是gp的值。我们在上电时,将_gp的值赋给gp寄存器就行了。

  • 18
  • 11月

最近,看了一小阵子的MIPS资料,做一下简单的记录吧。

第一是空间上的分配。MIPS空间上共分四个部份:
0x00000000 - 0x7fffffff 为kuser区,主要用于MMU映射,用于运行用户程序;<br />
0x80000000 - 0x9fffffff 为kseg0区,访问方式为Cache访问,主要用于运行无MMU系统的大部份程序或操作系统的核心程序;<br />
0xa0000000 - 0xbfffffff 为kseg1区,为无Cache方式访问。主要用于运行Bootloader程序,或映射寄存器。<br />
0xc0000000 - 0xffffffff 为kseg2区,MMU映射访问,用于运行一些管理态的程序。

需要注意的是:kseg0和kseg1都是映射上物理地址0x00000000-0x1fffffff上。
因些,程序运行的起始地址0xbfc00000实际上是物理地址0x1fc00000。

第二是寄存器。MIPS一共有32个通用寄存器。
$0 zero,该寄存器桓为0,用途较广,可用于清空其它寄存器,做一些空操作等。<br />
$1:at,主要保留用于汇编的一些宏指令。编译器可能使用到它。<br />
$2 - $3:v0 - v1,主要用于函数调用的定点返回值<br />
$4 - $7:a0 - a3,函数调用时传递的4个定点参数<br />
$8 - $15:t0 - t7,非保存的临时寄存器,可能被子程序改变其值。<br />
$16 - $23:s0 - s7,保存的临时寄存器,使用完毕需要还原原来的值。<br />
$24 - $25:t8 - t9,同t0 - t7;<br />
$28:gp,全局指针(Global Pointer),访问一些全局变量时会用到,具体用法暂时还不是太清楚 ;<br />
$29:sp,堆栈指针(Stack Pointer) ;<br />
$30:fp,帧指针(Frame Pointer) ,主要用于保存函数入口的堆栈指针。<br />
$31:ra ,执行jr,jalr后保存的返回PC地址。


第三是协处理器CP0。
用的最多的就是$12 SR和$13 CAUSE了。

暂时就先这些吧。等待以后补充。