MIPS体系结构 Q & A

MIPS体系结构 Q & A Part 0x01 寄存器与内存访问
最近问我MIPS体系结构相关问题的人越来越多,在这里小结一下。
一般在职业有段者水平的MIPS体系结构问题,都能在这里找到答案。
1.
Q: MIPS有多少一般用途的寄存器?
A: 32个。
2.
Q: 我在看反汇编代码的时候,看到一些寄存器名叫zero, a1, a2...还有sp, ra这样的名字。
为什么给他们起这些名字呢?
A: MIPS的通用寄存器中,按照编译器的通常的约定,某些寄存器是做专门用途的,比如sp就
是堆栈指针,ra是函数调用的返回地址等等。当然你也可以不按照这些约定编程,例如用$2存
放堆栈指针,$3存放返回地址,但这样的程序,和标准库链接就不能工作了
3.
Q: 为什么MIPS的SP寄存器也是通用寄存器呢?而且MIPS似乎没有专门的压栈/出栈指令
啊。
A: 这是MIPS这样的RISC处理器,同x86为代表的CISC处理器的重大区别之一。RISC没
有专门的硬件实现的堆栈寄存器/指令,改为软件实现,在函数入口堆栈指针递减,堆栈向低地
址生长,返回处恢复堆栈值,销毁堆栈帧

4.
Q: MIPS的堆栈用软件实现,那么,MIPS的函数调用开销会更大吗?
A: 这是x86为首的CISC支持者,经常诟病RISC的一点。但是,实际上,我们知道,MIPS
使用了4个GPR(一般用途寄存器)来传递前4个Word的函数
参数
,而x86只有EAX一个寄
存器用于传递函数参数。所以,如果函数的参数小于或等于4个word,那就不需要使用栈。我
们知道,大多数函数的参数都在4 个word以内。——所以,这一点不比太担心。另外,写太
多参数的函数时,建议使用结构体传递这些参数

5.
Q: MIPS的lh, lb 这样的指令,会改变寄存器里的前2个/1个字节,还是后2个/1个字节?
A:一般来说是低位。
6.
Q: MIPS是大端(Big-endian)的,还是小端的(Little-endian)?
A: 这是可以配置的。一般来说我们都使用大端模式,因为几乎所有的网络协议,数据包中的数
据字段均以大端模式封装。
7.
Q: 我在新闻报道看到“龙芯”和MIPS的指令95%相同,那么到底是哪部分不相同呢?
A: MIPS的四条“非对齐加载/存储”指令,是受专利法保护的,龙芯在没有获得授权的情况下不
能支持这四条指令。
8.
Q: 什么是非对齐加载/存储指令?什么情况下用这些指令呢?
A: MIPS的内存访问要求字节对齐。譬如,4字节访问指令,要求访问的开始地址能被4整除,
如0x8100223C. 如果访问0x8100223D这个地址,就会发生一个异常(Exception)。MIPS
处理器在处理这个异常时,把这样一次加载拆分为两次非对齐的加载来实现。
9.
Q: 可是x86上,似乎没有这样的限制啊?
A: 其实x86也有这个问题,非对齐访问会被拆成两次执行。只不过这一切都由硬件来完成,
代码级别透明——这样,一个不理解这个原理的程序员就非常容易在设计数据结构的时候犯下这
方面的错误,大量非对齐访问严重地影响系统的性能。
10.
Q: 那么,什么叫异常呢?
A: 要出门上课去了,土鳖抗铁牛
MIPS体系结构 Q & A Part 0x02 地址空间
11.
Q: MIPS的内存空间有多大?
A: 在32-bit模式下是4GB,用户态可以使用的空间是2GB。
12.
Q: 用户态是使用哪部分内存?
A: 虚拟地址0x00000000-0x7fffffff的2GB,叫做user space, mapped & cached.
13.
Q: 什么是用户态,还有哪些别的状态呢?
A: MIPS除了用户态还有内核态,在内核态下可以访问全部资源,但用户态只能访问部分,如
CP0、MMU等,用户态是不可以访问的。
14.
Q: 那么,怎样从用户态进入内核态呢?
A: 一般的正常渠道是执行syscall指令。另外还有trap/brackpoint等指令,会引发相应的异
常,进入内核态。当然程序错误引起的异常(如非对齐地址访问、未映射的地址访问)也会引发异
常,进入内核态。
15.
Q: 在内核态下可以访问多大的内存空间呢?
A: 4GB,但是从0x80000000到0xBFFFFFFF有特殊用途。0x80000000到0x9FFFFFFF,
和0xA0000000到0xBFFFFFFF这两段地址,硬件上指向同一段物理地址,0x00000000到
0x1fffffff。
16.
Q: 为什么要这样做?
A: 0xA0000000到0xBFFFFFFF是不经过Cache访问的,可以保证在上电时就可用,并且,
作为硬件IO寄存器映射地址时,不会被cache 扰乱。MIPS的上电启动地址,0xBFC00000
就在这段内存中。而0x80000000到0x9FFFFFFF这段地址是经过Cache映射的,内核代码
段和堆栈往往放在这一段内存,以保证访问和执行速度
17.
Q: 我的硬件工程师将bootrom连接到总线的0xBFC00000地址了,为什么系统不能启动?
A: 0xBFC00000是逻辑地址(程序中的地址),对应的物理地址(将逻辑分析仪连接在总线上,
捕捉到的地址)是0x1FC00000。
18.
Q: 那么,0xC0000000到0xFFFFFFFF的地址空间是干嘛的?
A: 可以作为内核使用的内存,比如kmalloc之类的函数分配使用。这段内存是通过MMU和
TLB映射的

19.
Q: 如果在用户态下,去访问0x80000000以上的地址会怎么样?
A: 发生一个异常。
20.
Q: 什么是MMU和TLB呢?
A: 这是另一个问题了,中午吃得太饱,有点困,土鳖抗铁牛...
MIPS体系结构 Q & A Part 0x03 CP0篇
20.
Q: CP0是干嘛的?
A: CP0是协处理器0,Co-Processor 0的缩写,MIPS最多可以支持4个协处理器,其中CP0
是强制要求实现的,用于处理器的状态控制等。它包括MMU、异常控制、Cache控制等功能。
21.
Q: MIPS的其他协处理器都有什么呢?
A: 这个和具体厂商的实现有关系了。CP1是浮点协处理器,是可选的,CP2和CP3是厂家自
定义的。
22.
Q: CP0里面都有哪些寄存器?一般用在什么场合?
A: CP0有32个寄存器,一般操作系统的内核才会接触到它们。主要有MMU类、异常控制类、
断点控制类等。
23.
Q: 这几类寄存器各有哪些呢?
A: MMU相关的,有Index,Random, EntryLo0, EntryLo1, Context, EntryHi, MageMask
和Wirds几个。具体用途介绍MMU的时候会提到。
异常控制相关的有Status, Cause, EPC, BadVaddr等。
断点控制的有Count, Compare, WatchLo, WatchHi等。
此外,还有PRId,用于确定CPU的类型;
LLAddr, 用于原子锁指令;
Config, 用于配置处理器。
24.
Q: 对CP0寄存器如何访问呢?
A: 有专门的指令访问。32bit读:
mfc0 rs, /*Move from co-processor 0*/
64bit读:
dmfc0 rs, /*Double move from co-processor 0*/
32bit写:
mtc0 rs, /*Move to co-processor 0*/
64bit写:
dmtc0 rs, /*Double move to co-processor 0*/
25.
Q: 对于CP0寄存器,如果只想修改其中的几个bit,该怎样做?
A: 只能先读取到GPR中,修改后写回
如:
mfc0 t0, SR
nop
and t0, BIT_MASK_ALPHA
or t0, BIT_MASK_BETA
mtc0 t0, SR
nop
26.
Q: 为什么要在mfc和mtc后面插入一个nop指令?
A: 这是为了避免CP0 hazard,简单地说就是执行完mfc或mtc指令之后,有可能要等待一
条指令的时间,数据才真正读取或写入到寄存器之中,在这个过程中如果修改相应寄存器会导致
错误的结果。
27.
Q: 为什么会有hazard现象?
A: 这是由MIPS高度流水的执行部件决定的。访问CP0所用的时间比较长,所以执行阶段尚
未完毕,下一条指令就会走到read阶段,导致出问题。
28.
Q: CP0的Watchlo和WatchHi寄存器是做什么的呢?
A: 这两个寄存器可以监控一块地址。WatchLo是低32bit,而WatchHi决定了监控地址的长
度和监控类型
。当满足条件访问到这块地址时会引发一个异常。对于内存写坏这样的问题,用这
种手段监测非常有用。具体可以看MIPS32 Architecture For Programmers, Vol III的第
8.32和8.33章节。
29.
Q: Counter和Compare是干嘛的?
A: 它们是一对冤家,Counter以CPU主频的一半速度自加,当它和Compare相等时就会触
发硬件中断5。它们联合使用,可以实现操作系统的时间中断。
30.
Q: 那么,硬件中断是什么呢?
A: 下次就要讲到中断和异常了,别心急啊~
MIPS体系结构 Q & A Part 0x04 系统异常篇
31.
Q: 异常和中断有什么区别?
A: 中断是异常的一种,占用0号异常。中断是异步发生的,一般由硬件事件触发(如某GPIO
引脚的电平跳变
),和指令执行阶段无关。而异常是指令触发发生的,也就是同步发生的
32.
Q: 什么叫“精确异常”?
A: "精确异常" 的原文是precise exception。precise这个词其实有“穷讲究”的意思。在这里
指的就是:当异常发生时,已经执行完memory阶段操作的指令均有效,未执行到该阶段的指
令,在流水线中一律丢弃。该异常的触发者为该条指令。
33.
Q: 对于TLB miss/Address error这样的异常,实际上为什么不会写入指令中的地址呢?
A: 因为这个时候指令只执行完ALU阶段,还没到Memory,所以被丢弃了。从处理器设计的
角度来看,这种非法指令本身也不该生效。
34.
Q: 发生异常的时候,是不是会进入内核态?
A: 是的。当然如果原本就在内核态,那么还是会在内核态。一般来说,操作系统通用的进入内
核,是通过一条syscall指令,产生类型为0x08的异常来实现的。
35.
Q: 我想知道,breakpoint, syscall和trap三种异常都是特殊指令触发的,它们有什么区别?
A: 一般说来,syscall指令是用于一般性的系统调用进入内核,类似于x86的调用门。
breakpoint是程序错误处理,例如,mips的除法指令,如果除数为0,会造成不确定的结果。
编译器在对除法表达式进行处理的时候,就做一个判断,如果除数为0,则执行指令:break 0x07。
如果运行时出现了除以0,那么,break 0x07这条指令会抛出一个breakpoint异常,子类型
为0x07——这样,程序员在debug的时候看见这个异常信息,就可以判断,程序中除数出现
了0。
trap异常是另一种debug手段产生的,由一系列trap指令触发。同break指令的区别是,不
同的trap指令有不同的触发条件,如某个寄存器满足一定的不等式的时候触发trap类异常。
36.
Q: NMI是什么异常?
A: NMI就是Non-maskable Interrupt,不可屏蔽中断,如看门狗、掉电等。
37.
Q: 我看到NMI的异常handler入口地址是0xbfc00000,和上电复位地址一样。那么如何区
分是复位运行还是NMI呢?
A: 看Cause和SR两个寄存器可以确定,然后进行不同的处理。
38.
Q: 异常发生的时候,系统会如何处理呢?
A: 首先是保存现场,按通用寄存器组epc/cause/status/badvaddr几个CP0寄存器,最
后是k0和k1的次序,将寄存器保存到异常栈。
然后,进行相应的异常处理。例如,对于Address error的异常,会对相应地址拆开两次加载(左
加载,右加载
),把取到的内容拼合放入目标寄存器;
最后,按保存寄存器的反向次序,恢复现场,执行这个指令次序返回:
mfc k0, epc
jr k0
rfe /* 在上一条jr指令的延迟槽中执行,这样可以保证原子性 */
而在MIPS III及以后的处理器中,从异常中返回不再需要这样的繁文缛节,只需要一条eret
指令。
39.
Q: 那么,对于无法处理的异常,比如访问0地址,系统会有怎样的行为呢?
A: 发生coredump。对于coredump,可以用gdb来分析,如:
richie@engshell-1>mips64-junos-gdb -c xxx.core xxx.elf
-c参数后面跟coredump文件名。
40.
Q: 还有,什么是延迟槽呢?
A: 这是和MIPS流水线相关的。以后在系统优化有关的章节,会详解。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值